mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
parent
594c61a0ff
commit
f5a2a634a1
21 changed files with 420 additions and 96 deletions
|
@ -13,7 +13,7 @@ bin = "tmp/main"
|
|||
# Customize binary.
|
||||
full_bin = "APP_ENV=dev APP_USER=air ./tmp/main"
|
||||
# Watch these filename extensions.
|
||||
include_ext = ["go", "tpl", "tmpl", "html"]
|
||||
include_ext = ["go", "tpl", "tmpl", "html", "conf"]
|
||||
# Ignore these filename extensions or directories.
|
||||
exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules", "upload"]
|
||||
# Watch these directories if you specified.
|
||||
|
|
2
frontend/components.d.ts
vendored
2
frontend/components.d.ts
vendored
|
@ -28,6 +28,8 @@ declare module '@vue/runtime-core' {
|
|||
ALayoutFooter: typeof import('ant-design-vue/es')['LayoutFooter']
|
||||
ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
|
||||
ALayoutSider: typeof import('ant-design-vue/es')['LayoutSider']
|
||||
AList: typeof import('ant-design-vue/es')['List']
|
||||
AListItem: typeof import('ant-design-vue/es')['ListItem']
|
||||
AMenu: typeof import('ant-design-vue/es')['Menu']
|
||||
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
|
||||
AModal: typeof import('ant-design-vue/es')['Modal']
|
||||
|
|
25
frontend/src/api/template.ts
Normal file
25
frontend/src/api/template.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import Curd from '@/api/curd'
|
||||
import http from '@/lib/http'
|
||||
|
||||
class Template extends Curd {
|
||||
get_config_list() {
|
||||
return http.get('template/configs')
|
||||
}
|
||||
|
||||
get_block_list() {
|
||||
return http.get('template/blocks')
|
||||
}
|
||||
|
||||
get_config(name: string) {
|
||||
return http.get('template/config/' + name)
|
||||
}
|
||||
|
||||
get_block(name: string) {
|
||||
return http.get('template/block/' + name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const template = new Template('/template')
|
||||
|
||||
export default template
|
|
@ -1,7 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import gettext from '@/gettext'
|
||||
|
||||
|
||||
import {ref, watch} from 'vue'
|
||||
|
||||
import {useSettingsStore} from '@/pinia'
|
||||
|
|
|
@ -39,7 +39,7 @@ const lang = computed(() => {
|
|||
|
||||
</script>
|
||||
<template>
|
||||
<a-config-provider :locale="lang">
|
||||
<a-config-provider :locale="lang" :autoInsertSpaceInButton="false">
|
||||
<a-layout style="min-height: 100%;">
|
||||
<div class="drawer-sidebar">
|
||||
<a-drawer
|
||||
|
|
|
@ -8,6 +8,7 @@ import ngx from '@/api/ngx'
|
|||
import {computed, reactive, ref} from 'vue'
|
||||
import {message} from 'ant-design-vue'
|
||||
import {useRouter} from 'vue-router'
|
||||
import template from '@/api/template'
|
||||
|
||||
const {$gettext, interpolate} = useGettext()
|
||||
|
||||
|
@ -39,7 +40,7 @@ function init() {
|
|||
|
||||
function save() {
|
||||
ngx.build_config(ngx_config).then(r => {
|
||||
domain.save(config.name, {content: r.content, enabled: true}).then(() => {
|
||||
domain.save(config.name, {name: config.name, content: r.content, enabled: true}).then(() => {
|
||||
message.success($gettext('Saved successfully'))
|
||||
|
||||
domain.enable(config.name).then(() => {
|
||||
|
@ -89,7 +90,6 @@ const has_server_name = computed(() => {
|
|||
<a-step :title="$gettext('Configure SSL')"/>
|
||||
<a-step :title="$gettext('Finished')"/>
|
||||
</a-steps>
|
||||
|
||||
<template v-if="current_step===0">
|
||||
<a-form layout="vertical">
|
||||
<a-form-item :label="$gettext('Configuration Name')">
|
||||
|
@ -97,7 +97,6 @@ const has_server_name = computed(() => {
|
|||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
|
||||
<directive-editor :ngx_directives="ngx_config.servers[0].directives"/>
|
||||
<br/>
|
||||
<location-editor :locations="ngx_config.servers[0].locations"/>
|
||||
|
|
|
@ -166,6 +166,7 @@ const modalClosable = ref(false)
|
|||
<a-modal
|
||||
:title="$gettext('Obtaining certificate')"
|
||||
v-model:visible="modalVisible"
|
||||
:mask-closable="modalClosable"
|
||||
:footer="null" :closable="modalClosable" force-render>
|
||||
<a-progress
|
||||
:stroke-color="progressStrokeColor"
|
||||
|
|
106
frontend/src/views/domain/ngx_conf/ConfigTemplate.vue
Normal file
106
frontend/src/views/domain/ngx_conf/ConfigTemplate.vue
Normal file
|
@ -0,0 +1,106 @@
|
|||
<script setup lang="ts">
|
||||
import {useGettext} from 'vue3-gettext'
|
||||
import template from '@/api/template'
|
||||
import {computed, ref} from 'vue'
|
||||
import {storeToRefs} from 'pinia'
|
||||
import {useSettingsStore} from '@/pinia'
|
||||
import Template from '@/views/template/Template.vue'
|
||||
import DirectiveEditor from '@/views/domain/ngx_conf/directive/DirectiveEditor.vue'
|
||||
import LocationEditor from '@/views/domain/ngx_conf/LocationEditor.vue'
|
||||
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
|
||||
|
||||
const {$gettext} = useGettext()
|
||||
const {language} = storeToRefs(useSettingsStore())
|
||||
const props = defineProps(['ngx_config', 'current_server_index'])
|
||||
|
||||
const blocks = ref([])
|
||||
const data: any = ref({})
|
||||
const visible = ref(false)
|
||||
|
||||
function get_block_list() {
|
||||
template.get_block_list().then(r => {
|
||||
blocks.value = r.data
|
||||
})
|
||||
}
|
||||
|
||||
get_block_list()
|
||||
|
||||
function view(name: string) {
|
||||
visible.value = true
|
||||
template.get_block(name).then(r => {
|
||||
data.value = r
|
||||
})
|
||||
}
|
||||
|
||||
const trans_description = computed(() => {
|
||||
return (item: any) => item.description?.[language.value] ?? item.description?.en ?? ''
|
||||
})
|
||||
|
||||
async function add() {
|
||||
|
||||
if (data.value.custom) {
|
||||
props.ngx_config.custom += '\n' + data.value.custom
|
||||
}
|
||||
|
||||
props.ngx_config.custom = props.ngx_config.custom.trim()
|
||||
|
||||
if (data.value.locations) {
|
||||
props.ngx_config.servers[props.current_server_index].locations.push(...data.value.locations)
|
||||
}
|
||||
|
||||
if (data.value.directives) {
|
||||
props.ngx_config.servers[props.current_server_index].directives.push(...data.value.directives)
|
||||
}
|
||||
|
||||
visible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h2 v-translate>Config Templates</h2>
|
||||
<div class="config-list-wrapper">
|
||||
<a-list
|
||||
:grid="{ gutter: 16, xs: 1, sm: 2, md: 2, lg: 2, xl: 2, xxl: 2, xxxl: 2 }"
|
||||
:data-source="blocks"
|
||||
>
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item>
|
||||
<a-card size="small" :title="item.name">
|
||||
<template #extra>
|
||||
<a-button type="link" @click="view(item.filename)">View</a-button>
|
||||
</template>
|
||||
<p>{{ $gettext('Author') }}: {{ item.author }}</p>
|
||||
<p>{{ $gettext('Description') }}: {{ trans_description(item) }}</p>
|
||||
</a-card>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</div>
|
||||
<a-modal
|
||||
:title="data.name"
|
||||
v-model:visible="visible"
|
||||
:mask="false"
|
||||
:ok-text="$gettext('Add')"
|
||||
@ok="add"
|
||||
>
|
||||
<p>{{ $gettext('Author') }}: {{ data.author }}</p>
|
||||
<p>{{ $gettext('Description') }}: {{ trans_description(data) }}</p>
|
||||
<template v-if="data.custom">
|
||||
<h2>{{ $gettext('Custom') }}</h2>
|
||||
<code-editor v-model:content="data.custom" default-height="150px"/>
|
||||
</template>
|
||||
<directive-editor v-if="data.directives" :ngx_directives="data.directives" :readonly="true"/>
|
||||
<br/>
|
||||
<location-editor v-if="data.locations" :locations="data.locations" :readonly="true"/>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.config-list-wrapper {
|
||||
max-height: 200px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
</style>
|
|
@ -7,7 +7,7 @@ import draggable from 'vuedraggable'
|
|||
|
||||
const {$gettext} = useGettext()
|
||||
|
||||
const props = defineProps(['locations'])
|
||||
const props = defineProps(['locations', 'readonly'])
|
||||
|
||||
let location = reactive({
|
||||
comments: '',
|
||||
|
@ -52,7 +52,7 @@ function remove(index: number) {
|
|||
<HolderOutlined/>
|
||||
{{ $gettext('Location') }}
|
||||
</template>
|
||||
<template #extra>
|
||||
<template #extra v-if="!readonly">
|
||||
<a-popconfirm @confirm="remove(index)"
|
||||
:title="$gettext('Are you sure you want to remove this location?')"
|
||||
:ok-text="$gettext('Yes')"
|
||||
|
@ -94,7 +94,7 @@ function remove(index: number) {
|
|||
</a-form>
|
||||
</a-modal>
|
||||
|
||||
<div>
|
||||
<div v-if="!readonly">
|
||||
<a-button block @click="add">{{ $gettext('Add Location') }}</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -6,6 +6,8 @@ import {useRoute, useRouter} from 'vue-router'
|
|||
import {useGettext} from 'vue3-gettext'
|
||||
import Cert from '@/views/domain/cert/Cert.vue'
|
||||
import LogEntry from '@/views/domain/ngx_conf/LogEntry.vue'
|
||||
import ConfigTemplate from '@/views/domain/ngx_conf/ConfigTemplate.vue'
|
||||
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
|
||||
|
||||
const {$gettext} = useGettext()
|
||||
|
||||
|
@ -151,6 +153,9 @@ watch(current_server_index, () => {
|
|||
<a-switch @change="change_tls"/>
|
||||
</a-form-item>
|
||||
|
||||
<h2>{{ $gettext('Custom') }}</h2>
|
||||
<code-editor v-model:content="ngx_config.custom" default-height="150px"/>
|
||||
|
||||
<a-tabs v-model:activeKey="current_server_index">
|
||||
<a-tab-pane :tab="'Server '+(k+1)" v-for="(v,k) in props.ngx_config.servers" :key="k">
|
||||
<log-entry
|
||||
|
@ -175,9 +180,11 @@ watch(current_server_index, () => {
|
|||
<h3 v-translate>Comments</h3>
|
||||
<a-textarea v-model:value="v.comments" :bordered="false"/>
|
||||
</template>
|
||||
|
||||
<directive-editor :ngx_directives="v.directives"/>
|
||||
<br/>
|
||||
<config-template :ngx_config="ngx_config"
|
||||
:current_server_index="current_server_index"/>
|
||||
<br/>
|
||||
<location-editor :locations="v.locations"/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -7,9 +7,7 @@ import DirectiveEditorItem from '@/views/domain/ngx_conf/directive/DirectiveEdit
|
|||
|
||||
const {$gettext} = useGettext()
|
||||
|
||||
const props = defineProps<{
|
||||
ngx_directives: any[]
|
||||
}>()
|
||||
const props = defineProps(['ngx_directives', 'readonly'])
|
||||
|
||||
const adding = ref(false)
|
||||
|
||||
|
@ -38,11 +36,13 @@ function onSave(idx: number) {
|
|||
<directive-editor-item @click="current_idx=index"
|
||||
:directive="directive"
|
||||
:current_idx="current_idx" :index="index"
|
||||
:ngx_directives="ngx_directives"/>
|
||||
:ngx_directives="ngx_directives"
|
||||
:readonly="readonly"
|
||||
/>
|
||||
</template>
|
||||
</draggable>
|
||||
|
||||
<directive-add :ngx_directives="ngx_directives"/>
|
||||
<directive-add v-if="!readonly" :ngx_directives="ngx_directives"/>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -10,7 +10,7 @@ import {message} from 'ant-design-vue'
|
|||
|
||||
const {$gettext, interpolate} = useGettext()
|
||||
|
||||
const props = defineProps(['directive', 'current_idx', 'index', 'ngx_directives'])
|
||||
const props = defineProps(['directive', 'current_idx', 'index', 'ngx_directives', 'readonly'])
|
||||
|
||||
function remove(index: number) {
|
||||
props.ngx_directives.splice(index, 1)
|
||||
|
@ -56,7 +56,8 @@ function save() {
|
|||
</template>
|
||||
</a-input>
|
||||
|
||||
<a-popconfirm @confirm="remove(index)"
|
||||
<a-popconfirm v-if="!readonly"
|
||||
@confirm="remove(index)"
|
||||
:title="$gettext('Are you sure you want to remove this directive?')"
|
||||
:ok-text="$gettext('Yes')"
|
||||
:cancel-text="$gettext('No')">
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
|
||||
"github.com/0xJacky/Nginx-UI/server/service"
|
||||
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||
"github.com/0xJacky/Nginx-UI/template"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -64,79 +60,43 @@ proxy_pass http://127.0.0.1:{{ HTTP01PORT }};
|
|||
}
|
||||
|
||||
func GetTemplateConfList(c *gin.Context) {
|
||||
configs, err := template.DistFS.ReadDir("conf")
|
||||
configList, err := service.GetTemplateList("conf")
|
||||
|
||||
if err != nil {
|
||||
ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
type configItem struct {
|
||||
Name string `json:"name"`
|
||||
Description map[string]string `json:"description"`
|
||||
Author string `json:"author"`
|
||||
}
|
||||
|
||||
var configList []configItem
|
||||
for _, config := range configs {
|
||||
func() {
|
||||
configListItem := configItem{
|
||||
Description: make(map[string]string),
|
||||
}
|
||||
|
||||
file, _ := template.DistFS.Open(filepath.Join("conf", config.Name()))
|
||||
defer file.Close()
|
||||
r := bufio.NewReader(file)
|
||||
bytes, _, err := r.ReadLine()
|
||||
if err == io.EOF {
|
||||
return
|
||||
}
|
||||
line := strings.TrimSpace(string(bytes))
|
||||
|
||||
if line != "# Nginx UI Template Start" {
|
||||
return
|
||||
}
|
||||
var content string
|
||||
for {
|
||||
bytes, _, err = r.ReadLine()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
line = strings.TrimSpace(string(bytes))
|
||||
if line == "# Nginx UI Template End" {
|
||||
break
|
||||
}
|
||||
content += line + "\n"
|
||||
}
|
||||
re := regexp.MustCompile(`# (\S+): (.*)`)
|
||||
matches := re.FindAllStringSubmatch(content, -1)
|
||||
for _, match := range matches {
|
||||
if len(match) < 3 {
|
||||
continue
|
||||
}
|
||||
key := match[1]
|
||||
switch {
|
||||
case key == "Name":
|
||||
configListItem.Name = match[2]
|
||||
case key == "Author":
|
||||
configListItem.Author = match[2]
|
||||
case strings.Contains(key, "Description"):
|
||||
re = regexp.MustCompile(`(\w+)\[(\w+)\]`)
|
||||
matches = re.FindAllStringSubmatch(key, -1)
|
||||
for _, m := range matches {
|
||||
if len(m) < 3 {
|
||||
continue
|
||||
}
|
||||
// lang => description
|
||||
configListItem.Description[m[2]] = match[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configList = append(configList, configListItem)
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": configList,
|
||||
})
|
||||
}
|
||||
|
||||
func GetTemplateBlockList(c *gin.Context) {
|
||||
configList, err := service.GetTemplateList("block")
|
||||
|
||||
if err != nil {
|
||||
ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": configList,
|
||||
})
|
||||
}
|
||||
|
||||
func GetTemplateBlock(c *gin.Context) {
|
||||
type resp struct {
|
||||
service.ConfigInfoItem
|
||||
service.ConfigDetail
|
||||
}
|
||||
detail, err := service.ParseTemplate("block", c.Param("name"))
|
||||
if err != nil {
|
||||
ErrHandler(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, resp{
|
||||
service.GetTemplateInfo("block", c.Param("name")),
|
||||
detail,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -13,6 +13,10 @@ const (
|
|||
Upstream = "upstream"
|
||||
)
|
||||
|
||||
func (s *NgxServer) ParseServer(directive gonginx.IDirective) {
|
||||
s.parseServer(directive)
|
||||
}
|
||||
|
||||
func (s *NgxServer) parseServer(directive gonginx.IDirective) {
|
||||
if directive.GetBlock() == nil {
|
||||
return
|
||||
|
@ -36,7 +40,9 @@ func (s *NgxServer) parseServer(directive gonginx.IDirective) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *NgxLocation) ParseLocation(directive gonginx.IDirective, deep int) {
|
||||
l.parseLocation(directive, deep)
|
||||
}
|
||||
func (l *NgxLocation) parseLocation(directive gonginx.IDirective, deep int) {
|
||||
if directive.GetBlock() == nil {
|
||||
return
|
||||
|
@ -52,6 +58,10 @@ func (l *NgxLocation) parseLocation(directive gonginx.IDirective, deep int) {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *NgxDirective) ParseDirective(directive gonginx.IDirective, deep int) {
|
||||
d.parseDirective(directive, deep)
|
||||
}
|
||||
|
||||
func (d *NgxDirective) parseDirective(directive gonginx.IDirective, deep int) {
|
||||
if directive.GetBlock() != nil {
|
||||
d.Params += directive.GetName() + " "
|
||||
|
@ -134,6 +144,7 @@ func parse(block gonginx.IBlock, ngxConfig *NgxConfig) {
|
|||
ngxConfig.parseCustom(v)
|
||||
}
|
||||
}
|
||||
ngxConfig.Custom = FmtCode(ngxConfig.Custom)
|
||||
}
|
||||
|
||||
func ParseNgxConfigByContent(content string) (ngxConfig *NgxConfig) {
|
||||
|
|
|
@ -77,6 +77,8 @@ func InitRouter() *gin.Engine {
|
|||
|
||||
g.GET("template", api.GetTemplate)
|
||||
g.GET("template/configs", api.GetTemplateConfList)
|
||||
g.GET("template/blocks", api.GetTemplateBlockList)
|
||||
g.GET("template/block/:name", api.GetTemplateBlock)
|
||||
|
||||
g.GET("cert/issue", api.IssueCert)
|
||||
|
||||
|
|
145
server/service/template.go
Normal file
145
server/service/template.go
Normal file
|
@ -0,0 +1,145 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
|
||||
"github.com/0xJacky/Nginx-UI/template"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tufanbarisyildirim/gonginx/parser"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ConfigInfoItem struct {
|
||||
Name string `json:"name"`
|
||||
Description map[string]string `json:"description"`
|
||||
Author string `json:"author"`
|
||||
Filename string `json:"filename"`
|
||||
}
|
||||
|
||||
func GetTemplateInfo(path, name string) (configListItem ConfigInfoItem) {
|
||||
configListItem = ConfigInfoItem{
|
||||
Description: make(map[string]string),
|
||||
Filename: name,
|
||||
}
|
||||
|
||||
file, _ := template.DistFS.Open(filepath.Join(path, name))
|
||||
defer file.Close()
|
||||
r := bufio.NewReader(file)
|
||||
bytes, _, err := r.ReadLine()
|
||||
if err == io.EOF {
|
||||
return
|
||||
}
|
||||
line := strings.TrimSpace(string(bytes))
|
||||
|
||||
if line != "# Nginx UI Template Start" {
|
||||
return
|
||||
}
|
||||
var content string
|
||||
for {
|
||||
bytes, _, err = r.ReadLine()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
line = strings.TrimSpace(string(bytes))
|
||||
if line == "# Nginx UI Template End" {
|
||||
break
|
||||
}
|
||||
content += line + "\n"
|
||||
}
|
||||
re := regexp.MustCompile(`# (\S+): (.*)`)
|
||||
matches := re.FindAllStringSubmatch(content, -1)
|
||||
for _, match := range matches {
|
||||
if len(match) < 3 {
|
||||
continue
|
||||
}
|
||||
key := match[1]
|
||||
switch {
|
||||
case key == "Name":
|
||||
configListItem.Name = match[2]
|
||||
case key == "Author":
|
||||
configListItem.Author = match[2]
|
||||
case strings.Contains(key, "Description"):
|
||||
re = regexp.MustCompile(`(\w+)\[(\w+)\]`)
|
||||
matches = re.FindAllStringSubmatch(key, -1)
|
||||
for _, m := range matches {
|
||||
if len(m) < 3 {
|
||||
continue
|
||||
}
|
||||
// lang => description
|
||||
configListItem.Description[m[2]] = match[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type ConfigDetail struct {
|
||||
Custom string `json:"custom"`
|
||||
nginx.NgxServer
|
||||
}
|
||||
|
||||
func ParseTemplate(path, name string) (c ConfigDetail, err error) {
|
||||
file, err := template.DistFS.Open(filepath.Join(path, name))
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "error tokenized template")
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
r := bufio.NewReader(file)
|
||||
var flag bool
|
||||
custom := ""
|
||||
content := ""
|
||||
for {
|
||||
bytes, _, err := r.ReadLine()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
orig := string(bytes)
|
||||
line := strings.TrimSpace(orig)
|
||||
switch {
|
||||
case line == "# Nginx UI Custom Start":
|
||||
flag = true
|
||||
case line == "# Nginx UI Custom End":
|
||||
flag = false
|
||||
case flag == true:
|
||||
custom += orig + "\n"
|
||||
case flag == false:
|
||||
content += orig + "\n"
|
||||
}
|
||||
}
|
||||
p := parser.NewStringParser(content)
|
||||
config := p.Parse()
|
||||
c.Custom = custom
|
||||
for _, d := range config.GetDirectives() {
|
||||
switch d.GetName() {
|
||||
case nginx.Location:
|
||||
l := &nginx.NgxLocation{}
|
||||
l.ParseLocation(d, 0)
|
||||
c.NgxServer.Locations = append(c.NgxServer.Locations, l)
|
||||
default:
|
||||
dir := &nginx.NgxDirective{}
|
||||
dir.ParseDirective(d, 0)
|
||||
c.NgxServer.Directives = append(c.NgxServer.Directives, dir)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetTemplateList(path string) (configList []ConfigInfoItem, err error) {
|
||||
configs, err := template.DistFS.ReadDir(path)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "error get template list")
|
||||
return
|
||||
}
|
||||
|
||||
for _, config := range configs {
|
||||
configList = append(configList, GetTemplateInfo(path, config.Name()))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -1,3 +1,9 @@
|
|||
location / {
|
||||
try_files $uri $uri/ /index.php;
|
||||
}
|
||||
# Nginx UI Template Start
|
||||
# Name: Codeigniter Rewrite
|
||||
# Description[en]: Codeigniter URL Rewrite Config
|
||||
# Description[zh_CN]: Codeigniter 伪静态配置
|
||||
# Author: @0xJacky
|
||||
# Nginx UI Template End
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php;
|
||||
}
|
||||
|
|
13
template/block/enable-php-8.conf
Normal file
13
template/block/enable-php-8.conf
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Nginx UI Template Start
|
||||
# Name: PHP8.1
|
||||
# Description[en]: Enabled PHP 8.1 Config
|
||||
# Description[zh_CN]: 启用 PHP 8.1 配置
|
||||
# Author: @0xJacky
|
||||
# Nginx UI Template End
|
||||
location ~ [^/]\.php(/|$)
|
||||
{
|
||||
try_files $uri =404;
|
||||
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi.conf;
|
||||
}
|
|
@ -1,3 +1,9 @@
|
|||
location / {
|
||||
try_files $uri $uri/ /server.php?$query_string;
|
||||
}
|
||||
# Nginx UI Template Start
|
||||
# Name: Laravel Rewrite
|
||||
# Description[en]: Laravel URL Rewrite Config
|
||||
# Description[zh_CN]: Laravel 伪静态配置
|
||||
# Author: @0xJacky
|
||||
# Nginx UI Template End
|
||||
location / {
|
||||
try_files $uri $uri/ /server.php?$query_string;
|
||||
}
|
||||
|
|
15
template/block/reverse_proxy.conf
Normal file
15
template/block/reverse_proxy.conf
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Nginx UI Template Start
|
||||
# Name: Reverse Proxy
|
||||
# Description[en]: Reverse Proxy Config
|
||||
# Description[zh_CN]: 反向代理配置
|
||||
# Author: @0xJacky
|
||||
# Nginx UI Template End
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:9000/;
|
||||
proxy_redirect off;
|
||||
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;
|
||||
client_max_body_size 1000m;
|
||||
}
|
26
template/block/reverse_proxy_ws.conf
Normal file
26
template/block/reverse_proxy_ws.conf
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Nginx UI Template Start
|
||||
# Name: Reverse Proxy WebSocket
|
||||
# Description[en]: Reverse Proxy with WebSocket Config
|
||||
# Description[zh_CN]: 反向代理 WebSocket 配置
|
||||
# Author: @0xJacky
|
||||
# Nginx UI Template End
|
||||
|
||||
# Nginx UI Custom Start
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
# Nginx UI Custom End
|
||||
|
||||
location / {
|
||||
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/;
|
||||
proxy_redirect off;
|
||||
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;
|
||||
client_max_body_size 1000m;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue