Nginx部署Go项目

如何在 Ubuntu 云服务器上使用Nginx部署 Go 语言程序?

Nginx 是一个免费的、开源的、高性能的 HTTP 和反向代理服务,主要负责负载一些访问量比较大的站点。Nginx 可以作为一个独立的 Web 服务,也可以用来给 Apache 或是其他的 Web 服务做反向代理。相比于 Apache,Nginx 可以处理更多的并发连接,而且每个连接的内存占用的非常小。

Nginx的安装

没有安装的可以看我的这篇文章,这里就不再水字数了,哈哈 :relieved:

Nginx常用命令

在这里补充几个 Nginx 常用命令。

1
2
3
4
nginx -s stop    # 停止 Nginx 服务
nginx -s reload # 重新加载配置文件
nginx -s quit # 平滑停止 Nginx 服务
nginx -t # 测试配置文件是否正确

Nginx反向代理部署

推荐使用 nginx 作为反向代理来部署我们的程序,按下面的内容修改 nginx 的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
worker_processes  1;

events {
worker_connections 1024;
}

http {
include mime.types;
default_type application/octet-stream;

sendfile on;
keepalive_timeout 65;

server {
listen 80;
server_name localhost;

access_log /var/log/bluebell-access.log;
error_log /var/log/bluebell-error.log;

location / {
proxy_pass http://127.0.0.1:8084;
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;
}
}
}

执行下面的命令检查配置文件语法:

1
nginx -t

执行下面的命令重新加载配置文件:

1
nginx -s reload

接下来就是打开浏览器查看网站是否正常了。

当然我们还可以使用 nginxupstream 配置来添加多个服务器地址实现负载均衡。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
worker_processes  1;

events {
worker_connections 1024;
}

http {
include mime.types;
default_type application/octet-stream;

sendfile on;
keepalive_timeout 65;

upstream backend {
server 127.0.0.1:8084;
# 这里需要填真实可用的地址,默认轮询
#server backend1.example.com;
#server backend2.example.com;
}

server {
listen 80;
server_name localhost;

access_log /var/log/bluebell-access.log;
error_log /var/log/bluebell-error.log;

location / {
proxy_pass http://backend/;
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;
}
}
}

Nginx分离静态文件请求

上面的配置是简单的使用 nginx 作为反向代理处理所有的请求并转发给我们的 Go 程序处理,其实我们还可以有选择的将静态文件部分的请求直接使用 nginx 处理,而将 API 接口类的动态处理请求转发给后端的 Go 程序来处理

分离静态文件请求图示

下面继续修改我们的 nginx 的配置文件来实现上述功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
worker_processes  1;

events {
worker_connections 1024;
}

http {
include mime.types;
default_type application/octet-stream;

sendfile on;
keepalive_timeout 65;

server {
listen 80;
server_name bluebell;

access_log /var/log/bluebell-access.log;
error_log /var/log/bluebell-error.log;

# 静态文件请求
location ~ .*\.(gif|jpg|jpeg|png|js|css|eot|ttf|woff|svg|otf)$ {
access_log off;
expires 1d;
root /data/app/bluebell;
}

# index.html页面请求
# 因为是单页面应用这里使用 try_files 处理一下,避免刷新页面时出现404的问题
location / {
root /data/app/bluebell/templates;
index index.html;
try_files $uri $uri/ /index.html;
}

# API请求
location /api {
proxy_pass http://127.0.0.1:8084;
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;
}
}
}

前后端分开部署

前后端的代码没必要都部署到相同的服务器上,也可以分开部署到不同的服务器上,下图是前端服务将 API 请求转发至后端服务的方案。

前后端分开部署方案1

上面的部署方案中,所有浏览器的请求都是直接访问前端服务,而如果是浏览器直接访问后端API服务的部署模式下,如下图。

此时前端和后端通常不在同一个域下,我们还需要在后端代码中添加跨域支持。

前后端分开部署方案2

这里使用github.com/gin-contrib/cors库来支持跨域请求。

最简单的允许跨域的配置是使用cors.Default(),它默认允许所有跨域请求。

1
2
3
4
5
6
7
8
9
func main() {
router := gin.Default()
// same as
// config := cors.DefaultConfig()
// config.AllowAllOrigins = true
// router.Use(cors.New(config))
router.Use(cors.Default())
router.Run()
}

此外,还可以使用cors.Config自定义具体的跨域请求相关配置项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"time"

"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)

func main() {
router := gin.Default()
// CORS for https://foo.com and https://github.com origins, allowing:
// - PUT and PATCH methods
// - Origin header
// - Credentials share
// - Preflight requests cached for 12 hours
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://foo.com"},
AllowMethods: []string{"PUT", "PATCH"},
AllowHeaders: []string{"Origin"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
AllowOriginFunc: func(origin string) bool {
return origin == "https://github.com"
},
MaxAge: 12 * time.Hour,
}))
router.Run()
}

参考资料

部署Go语言项目的 N 种方法