├── README.md ├── conf └── app.conf ├── controllers └── default.go ├── main.go ├── models ├── base.go ├── domain.go └── option.go ├── nginx.db ├── nginxconf.exe ├── nginxconf.exe~ ├── routers └── router.go ├── template ├── domainconf.tpl └── domainlocalconf.tpl └── views ├── domain.tpl ├── domainconf.tpl └── index.tpl /README.md: -------------------------------------------------------------------------------- 1 | # nginxconf 2 | web页面自由配置nginx虚拟主机 3 | 4 | 该项目基于golang的 beego web框架 主要实现了一下功能 5 | 创建新的nginx代理配置文件 并自动调用 nginx reload 命令 6 | 暂时没有实现删除配置文件命令 7 | 8 | #应用场景 9 | nginx需要实现代理访问多个主机,操作人员无需懂得nginx配置只需要在web页面点击下鼠标即可 10 | 多个 golang 应用程序在服务器后台运行在非80端口,nginx更具不同的域名代理访问不同的golang应用程序 11 | 12 | #改造后可以做什么? 13 | 增加设置多个nginx配置模板,可以实现负载均衡、自动配置虚拟主机等高级的nginx的功能 14 | nginx配置模板为nginxconf/template/domainlocalconf.tpl 15 | 16 | #该项目使用帮助 17 | 由于我在windows上编译的,暂时没有找到交叉编译sqlite到linux的方法,该程序的数据存储于sqlite,虽然我在linux环境下编译出来了32位的编译文件,但是由于不会上传到github上,如果需要可以发送邮件到1935873589@qq.com. 运行成功后输入用户名 admin 18 | 密码 adminpwd,如果需要更改密码请在/conf/app.conf配置文件里面更改 19 | user = admin 20 | pwd = adminpwd 21 | 22 | #该项目用到的库 23 | beego "github.com/astaxie/beego" 24 | go-sh "github.com/codeskyblue/go-sh" 25 | 26 | 27 | -------------------------------------------------------------------------------- /conf/app.conf: -------------------------------------------------------------------------------- 1 | appname = nginxconf 2 | httpport = 8091 3 | runmode = dev 4 | user = admin 5 | pwd = adminpwd 6 | sessionon = true -------------------------------------------------------------------------------- /controllers/default.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "bufio" 5 | "ccxt.com/nginxconf/models" 6 | "fmt" 7 | "github.com/astaxie/beego" 8 | "github.com/astaxie/beego/orm" 9 | //"github.com/astaxie/beego/session" 10 | "github.com/codeskyblue/go-sh" 11 | "io" 12 | "os" 13 | "strconv" 14 | "text/template" 15 | ) 16 | 17 | type MainController struct { 18 | beego.Controller 19 | } 20 | 21 | func (c *MainController) Prepare() { 22 | // _, action := c.GetControllerAndAction() 23 | // fmt.Println(action) 24 | // if action == "Index" || action == "Login" { 25 | 26 | // } else { 27 | // if c.GetSession("user") != nil && c.GetSession("pwd") != nil { 28 | // userhttp := c.GetSession("user").(string) 29 | // pwdhttp := c.GetSession("pwd").(string) 30 | // user := beego.AppConfig.String("user") 31 | // pwd := beego.AppConfig.String("pwd") 32 | // if userhttp == user && pwdhttp == pwd { 33 | // //c.Redirect("/domain", 302) 34 | // c.SetSession("user", userhttp) 35 | // c.SetSession("pwd", pwdhttp) 36 | // } else { 37 | // c.Redirect("/", 302) 38 | // } 39 | // } else { 40 | // c.Redirect("/", 302) 41 | // } 42 | // } 43 | 44 | } 45 | 46 | func (c *MainController) Index() { 47 | c.Data["Website"] = "beego.me" 48 | c.Data["Email"] = "astaxie@gmail.com" 49 | c.TplNames = "index.tpl" 50 | } 51 | 52 | func (c *MainController) Login() { 53 | userhttp := c.GetString("user") 54 | pwdhttp := c.GetString("pwd") 55 | user := beego.AppConfig.String("user") 56 | pwd := beego.AppConfig.String("pwd") 57 | fmt.Println(userhttp) 58 | fmt.Println(pwdhttp) 59 | fmt.Println(user) 60 | fmt.Println(pwd) 61 | if userhttp == user && pwdhttp == pwd { 62 | c.Redirect("/domain", 302) 63 | c.SetSession("user", userhttp) 64 | c.SetSession("pwd", pwdhttp) 65 | } else { 66 | c.Redirect("/", 302) 67 | } 68 | 69 | } 70 | 71 | /**虚拟主机列表**/ 72 | func (c *MainController) Domain() { 73 | var ( 74 | domian models.Domain 75 | domians []models.Domain 76 | option models.Option 77 | //options []models.Option 78 | ) 79 | optionerr := option.Query().Filter("name", "confdir").One(&option) 80 | domian.Query().All(&domians) 81 | 82 | if optionerr == nil { 83 | c.Data["option"] = option 84 | } else { 85 | 86 | } 87 | 88 | if len(domians) > 0 { 89 | c.Data["domians"] = domians 90 | } else { 91 | 92 | } 93 | c.TplNames = "domain.tpl" 94 | } 95 | 96 | /**设置nginx路径**/ 97 | func (c *MainController) Addconfdir() { 98 | var ( 99 | option models.Option 100 | ) 101 | //optionerr := option.Query().Filter("name", "confdir").One(&option) 102 | confdir := c.GetString("confdir") 103 | _, err := option.Query().Filter("name", "confdir").Update(orm.Params{"value": confdir}) 104 | if err != nil { 105 | c.Ctx.WriteString("设置失败,错误:" + err.Error()) 106 | } 107 | c.Ctx.WriteString("设置成功,请返回刷新列表") 108 | } 109 | 110 | /**添加虚拟主机 **/ 111 | func (c *MainController) Addomain() { 112 | var ( 113 | domian models.Domain 114 | //domians []models.Domain 115 | ) 116 | // domian.Query().All(&domians) 117 | // if len(domians) > 0 { 118 | // c.Data["domians"] = domians 119 | // } else { 120 | 121 | // } 122 | 123 | Server_name := c.GetString("Server_name") 124 | Port, _ := c.GetInt64("Port") 125 | Proxy_pass := c.GetString("Proxy_pass") 126 | Access_log := c.GetString("Access_log") 127 | Expires := c.GetString("Expires") 128 | Root := c.GetString("Root") 129 | 130 | domian.Access_log = Access_log 131 | domian.Expires = Expires 132 | domian.Port = Port 133 | domian.Proxy_pass = Proxy_pass 134 | domian.Root = Root 135 | domian.Server_name = Server_name 136 | _, err := models.AddDomain(&domian) 137 | if err != nil { 138 | c.Ctx.WriteString("添加失败,错误:" + err.Error()) 139 | } 140 | c.Ctx.WriteString("添加成功,请返回刷新列表") 141 | } 142 | 143 | /**虚拟主机列表**/ 144 | func (c *MainController) Create() { 145 | var ( 146 | domian models.Domain 147 | //tmpdomian models.Domain 148 | //domians []models.Domain 149 | option models.Option 150 | id int64 151 | confdir string 152 | ) 153 | 154 | if id, _ = strconv.ParseInt(c.Ctx.Input.Param(":id"), 10, 64); id < 1 { 155 | c.Ctx.WriteString("错误的id") 156 | //this.RenderString() 157 | return 158 | } 159 | 160 | optionerr := option.Query().Filter("name", "confdir").One(&option) 161 | if optionerr == nil { 162 | confdir = option.Value 163 | } else { 164 | confdir = "" 165 | } 166 | 167 | domian.Query().Filter("id", id).One(&domian) 168 | // domian.Access_log 169 | // domian.Expires 170 | // domian.Port 171 | // domian.Proxy_pass 172 | // domian.Root 173 | // domian.Server_name 174 | paththis, _ := os.Getwd() 175 | d := string(os.PathSeparator) 176 | fmt.Println(paththis) 177 | //path = paththis + d + "static" + d + "upload" + d + path + d + h.Filename 178 | pathdir := paththis + d + "views" + d + "domainconf.tpl" 179 | 180 | s1, tmperr := template.ParseFiles(pathdir) 181 | if tmperr != nil { 182 | fmt.Println(tmperr.Error()) 183 | } 184 | fmt.Println(confdir) 185 | /**********test write********* / 186 | file, err := os.Create(confdir + d + domian.Server_name + ".conf") 187 | if err != nil { 188 | fmt.Println("writer", err) 189 | c.Ctx.WriteString("not Create ok") 190 | return 191 | } 192 | defer file.Close() 193 | //writer := bufio.NewWriter(file) 194 | /**********test write end********* / 195 | //s1.Execute(c.Ctx.ResponseWriter, domian)//这个也可以使用 196 | //domiant := models.Domain{Id: 1, Server_name: "", Port: 80, Proxy_pass: "", Access_log: "", Expires: "", Root: ""} 197 | exeuteerr := s1.Execute(file, domian) 198 | if exeuteerr != nil { 199 | fmt.Println(exeuteerr.Error()) 200 | } 201 | 202 | /****test writer to string****/ 203 | r, w := io.Pipe() 204 | var tmp string 205 | tmp = "" 206 | //data := make([]byte, 2048) 207 | //r.Read(data) 208 | 209 | data := make([]byte, 1024) 210 | 211 | go func() { 212 | for n, err := r.Read(data); err == nil; n, err = r.Read(data) { 213 | fmt.Printf("%s", data[:n]) 214 | tmp = tmp + string(data[:n]) 215 | } 216 | // for { 217 | // r.Read(data) 218 | // tmp = tmp + string(data) 219 | // //fmt.Println(string(b[0:])) //hello widuu 220 | // } 221 | }() 222 | 223 | //var b [128]byte 224 | // go func() { 225 | // for { 226 | // r.Read(b[0:]) 227 | // tmp = tmp + string(b[0:]) 228 | // //fmt.Println(string(b[0:])) //hello widuu 229 | // } 230 | 231 | // }() 232 | 233 | s1.Execute(w, domian) 234 | fmt.Println(tmp) 235 | //fmt.Println("read number", n) 236 | 237 | /********/ 238 | 239 | csh := sh.Command("/etc/init.d/nginx", "reload") 240 | csh.Start() 241 | csh.Run() 242 | msgcsh, _ := csh.Output() 243 | fmt.Println(msgcsh) 244 | 245 | msg, _ := sh.Command("/etc/init.d/nginx", "reload").Output() 246 | 247 | c.Ctx.WriteString(string(msg)) 248 | 249 | c.Ctx.WriteString("ok") 250 | //writer.Flush() 251 | 252 | //this.RenderString() 253 | return 254 | //c.TplNames = "domain.tpl" 255 | } 256 | 257 | /**删除虚拟主机**/ 258 | func (c *MainController) Delete() { 259 | var ( 260 | domian models.Domain 261 | id int64 262 | ) 263 | 264 | if id, _ = strconv.ParseInt(c.Ctx.Input.Param(":id"), 10, 64); id < 1 { 265 | c.Ctx.WriteString("错误的id") 266 | //this.RenderString() 267 | return 268 | } 269 | 270 | _, err := domian.Query().Filter("id", id).Delete() 271 | if err != nil { 272 | c.Ctx.WriteString("删除失败,错误:" + err.Error()) 273 | } 274 | c.Ctx.WriteString("删除成功,请返回刷新列表") 275 | } 276 | 277 | func writeResult(vals []int, outfile string) error { 278 | 279 | file, err := os.Create(outfile) 280 | if err != nil { 281 | fmt.Println("writer", err) 282 | return err 283 | } 284 | defer file.Close() 285 | 286 | writer := bufio.NewWriter(file) 287 | for _, v := range vals { 288 | 289 | writer.WriteString(strconv.Itoa(v)) 290 | writer.WriteString("\n") 291 | writer.Flush() 292 | } 293 | 294 | return err 295 | } 296 | 297 | func (c *MainController) Tes() { 298 | // test := beego.GlobalSessions 299 | // test.SessionStart(w, r) 300 | // test() 301 | c.Ctx.WriteString("ok") 302 | } 303 | 304 | func test() { 305 | // var ( 306 | // con1 beego.Controller 307 | // con2 *beego.Controller 308 | // ) 309 | // beego. 310 | // con1.SetSession("name", "value") 311 | // con2.SetSession("name", "value") 312 | // test2 := con1.GetSession("name") 313 | // //con1 = new(beego.Controller) 314 | // test := con2.GetSession("name") 315 | // fmt.Println(test) 316 | // fmt.Println(test2) 317 | 318 | } 319 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | //"ccxt.com/nginxconf/controllers" 5 | _ "ccxt.com/nginxconf/routers" 6 | "github.com/astaxie/beego" 7 | ) 8 | 9 | func main() { 10 | beego.Run() 11 | } 12 | -------------------------------------------------------------------------------- /models/base.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "crypto/md5" 5 | "fmt" 6 | //"github.com/astaxie/beego" 7 | "github.com/astaxie/beego/orm" 8 | //_ "github.com/go-sql-driver/mysql" 9 | _ "github.com/mattn/go-sqlite3" 10 | "net/url" 11 | "strings" 12 | "time" 13 | ) 14 | 15 | func init() { 16 | //dbhost := beego.AppConfig.String("dbhost") 17 | //dbport := beego.AppConfig.String("dbport") 18 | //dbuser := beego.AppConfig.String("dbuser") 19 | //dbpassword := beego.AppConfig.String("dbpassword") 20 | //dbname := beego.AppConfig.String("dbname") 21 | //if dbport == "" { 22 | // dbport = "3306" 23 | //} 24 | //dsn := dbuser + ":" + dbpassword + "@tcp(" + dbhost + ":" + dbport + ")/" + dbname + "?charset=utf8" 25 | orm.DefaultTimeLoc = time.UTC 26 | orm.RegisterDataBase("default", "sqlite3", "nginx.db") 27 | //orm.RegisterDataBase("default", "mysql", dsn) 28 | orm.RegisterModel(new(Domain), new(Option)) 29 | //, new(Option)) 30 | } 31 | 32 | func Md5(buf []byte) string { 33 | hash := md5.New() 34 | hash.Write(buf) 35 | return fmt.Sprintf("%x", hash.Sum(nil)) 36 | } 37 | 38 | func Rawurlencode(str string) string { 39 | return strings.Replace(url.QueryEscape(str), "+", "%20", -1) 40 | } 41 | -------------------------------------------------------------------------------- /models/domain.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/astaxie/beego/orm" 5 | ) 6 | 7 | type Domain struct { 8 | Id int64 `orm:"column(id);auto"` 9 | Server_name string `orm:"column(server_name)"` 10 | Port int64 `orm:"column(port)"` 11 | Proxy_pass string `orm:"column(proxy_pass)"` 12 | Access_log string `orm:"column(access_log)"` 13 | Expires string `orm:"column(expires)"` 14 | Root string `orm:"column(root)"` 15 | } 16 | 17 | //高级查询 18 | func (m *Domain) Query() orm.QuerySeter { 19 | return orm.NewOrm().QueryTable(m) 20 | } 21 | 22 | //读取字段相同的记录 23 | func (m *Domain) Read(fields ...string) error { 24 | if err := orm.NewOrm().Read(m, fields...); err != nil { 25 | return err 26 | } 27 | return nil 28 | } 29 | 30 | func AddDomain(m *Domain) (id int64, err error) { 31 | o := orm.NewOrm() 32 | id, err = o.Insert(m) 33 | return 34 | } 35 | -------------------------------------------------------------------------------- /models/option.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/astaxie/beego/orm" 5 | ) 6 | 7 | type Option struct { 8 | Id int64 `orm:"column(id);auto"` 9 | Name string `orm:"column(name)"` 10 | Value string `orm:"column(value)"` 11 | } 12 | 13 | //高级查询 14 | func (m *Option) Query() orm.QuerySeter { 15 | return orm.NewOrm().QueryTable(m) 16 | } 17 | 18 | //读取字段相同的记录 19 | func (m *Option) Read(fields ...string) error { 20 | if err := orm.NewOrm().Read(m, fields...); err != nil { 21 | return err 22 | } 23 | return nil 24 | } 25 | 26 | func AddOption(m *Option) (id int64, err error) { 27 | o := orm.NewOrm() 28 | id, err = o.Insert(m) 29 | return 30 | } 31 | -------------------------------------------------------------------------------- /nginx.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasth/nginxconf/fb1a9ee37ec7bf0ad002bcedddebbf32b1e9181e/nginx.db -------------------------------------------------------------------------------- /nginxconf.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasth/nginxconf/fb1a9ee37ec7bf0ad002bcedddebbf32b1e9181e/nginxconf.exe -------------------------------------------------------------------------------- /nginxconf.exe~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasth/nginxconf/fb1a9ee37ec7bf0ad002bcedddebbf32b1e9181e/nginxconf.exe~ -------------------------------------------------------------------------------- /routers/router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "ccxt.com/nginxconf/controllers" 5 | "github.com/astaxie/beego" 6 | ) 7 | 8 | func init() { 9 | beego.Router("/", &controllers.MainController{}, "*:Index") 10 | beego.Router("/login", &controllers.MainController{}, "*:Login") 11 | beego.Router("/domain", &controllers.MainController{}, "*:Domain") 12 | beego.Router("/addserver", &controllers.MainController{}, "*:Addomain") 13 | beego.Router("/create/:id", &controllers.MainController{}, "*:Create") 14 | beego.Router("/delete/:id", &controllers.MainController{}, "*:Delete") 15 | beego.Router("/addconfdir", &controllers.MainController{}, "*:Addconfdir") 16 | beego.Router("/test", &controllers.MainController{}, "*:Tes") 17 | 18 | } 19 | -------------------------------------------------------------------------------- /template/domainconf.tpl: -------------------------------------------------------------------------------- 1 | server { 2 | listen {{.Port}}; 3 | server_name {{.Server_name}}; 4 | 5 | charset utf-8; 6 | access_log {{.Access_log}}; 7 | 8 | location /(css|js|fonts|img)/ { 9 | access_log off; 10 | 11 | proxy_pass {{.Proxy_pass}} ; 12 | proxy_redirect off; 13 | proxy_set_header Host $host; 14 | proxy_cache cache_one; 15 | proxy_cache_valid 200 302 24h; 16 | proxy_cache_valid 301 30d; 17 | proxy_cache_valid any 5m; 18 | expires {{.Expires}}; 19 | 20 | try_files $uri @backend; 21 | } 22 | 23 | location / { 24 | try_files /_not_exists_ @backend; 25 | } 26 | 27 | location @backend { 28 | proxy_set_header X-Forwarded-For $remote_addr; 29 | proxy_set_header Host $http_host; 30 | 31 | proxy_pass {{.Proxy_pass}}; 32 | } 33 | } -------------------------------------------------------------------------------- /template/domainlocalconf.tpl: -------------------------------------------------------------------------------- 1 | server { 2 | listen {{.Port}}; 3 | server_name {{.Server_name}}; 4 | 5 | charset utf-8; 6 | access_log {{.Access_log}}; 7 | 8 | location /(css|js|fonts|img)/ { 9 | access_log off; 10 | expires 1d; 11 | 12 | root {{.Root}}; 13 | 14 | try_files $uri @backend; 15 | } 16 | 17 | location / { 18 | try_files /_not_exists_ @backend; 19 | } 20 | 21 | location @backend { 22 | proxy_set_header X-Forwarded-For $remote_addr; 23 | proxy_set_header Host $http_host; 24 | 25 | proxy_pass {{.Proxy_pass}}; 26 | } 27 | } -------------------------------------------------------------------------------- /views/domain.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | domain 5 | 6 | 7 | 8 | {{$option :=.option}} 9 |

设置配置文件路径

10 |
11 | 当前nginx配置文件放置路径(最后面不加/或者\): 12 | 13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {{if .domians}} 28 | {{range $k, $v := .domians}} 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | {{end}} 41 | {{else}} 42 | 43 | 44 | 暂无主机配置 45 | {{end}} 46 |
ID 主机域名 主机端口 主机代理地址 访问日志 静态资源保留时间 静态资源目录 操作
{{$v.Id}}
{{$v.Server_name}}
{{$v.Port}}
{{$v.Proxy_pass}}
{{$v.Access_log}}
{{$v.Expires}}
{{$v.Root}}
生效 删除
47 |

添加虚拟主机

48 |
49 | 50 | 主机域名(不需要添加http://):
51 | 主机端口:
52 | 主机代理地址(需要添加http://):
53 | 访问日志(不需要则设置为off):
54 | 静态资源保留时间(不需要则设置为例如1天:1d):
55 | 静态资源目录(系统绝对路径):
56 | 57 |
58 | 59 | {{if compare .isadd 1}} 60 | 添加域名成功 61 | {{end}} 62 | 63 | 64 |
  
65 | 如果选择代理缓存则需要在nginx http 配置中添加下列代码
66 |   
67 | proxy_connect_timeout 10;
68 | proxy_read_timeout 180;
69 | proxy_send_timeout 5;
70 | proxy_buffer_size 16k;
71 | proxy_buffers 4 64k;
72 | proxy_busy_buffers_size 256k;
73 | proxy_temp_file_write_size 256k;
74 | proxy_temp_path /tmp/temp_dir;
75 | proxy_cache_path /home/cache levels=1:2 keys_zone=cache_one:100m inactive=1d max_size=10g; 
76 |   
77 | 
78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /views/domainconf.tpl: -------------------------------------------------------------------------------- 1 | server { 2 | listen {{.Port}}; 3 | server_name {{.Server_name}}; 4 | 5 | charset utf-8; 6 | access_log {{.Access_log}}; 7 | 8 | location /(css|js|fonts|img)/ { 9 | access_log off; 10 | expires {{.Expires}}; 11 | 12 | root "{{.Root}}"; 13 | try_files $uri @backend; 14 | } 15 | 16 | location / { 17 | try_files /_not_exists_ @backend; 18 | } 19 | 20 | location @backend { 21 | proxy_set_header X-Forwarded-For $remote_addr; 22 | proxy_set_header Host $http_host; 23 | 24 | proxy_pass {{.Proxy_pass}}; 25 | } 26 | } -------------------------------------------------------------------------------- /views/index.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Beego 6 | 7 | 8 | 62 | 63 | 64 | 65 |
66 |
67 |
68 |
69 |
70 | 管理员帐号: 71 | 管理员密码: 72 | 73 |
74 |

Welcome to Beego!

75 |

76 | Beego is a simple & powerful Go web framework which is inspired by tornado and sinatra. 77 |
78 | Official website: {{.Website}} 79 |
80 | Contact me: {{.Email}} 81 |

82 |
83 |
84 |
85 |
86 | 87 | 88 | --------------------------------------------------------------------------------