使用Apache多个VirtualHosts的Golang webapp

时间:2018-02-18 15:31:00

标签: apache go webdeploy virtual-hosts

遗憾的是,我无法在生产服务器上部署基本的Golang WebApp。经过许多文档和教程后,我了解到我需要将Golang WebApp作为守护进程运行。

首先要做的事情是:生产服务器是运行Ubuntu 16.04的单个IP,基于Apache的多个VirtualHosts /etc/apache2/sites-enabled/

Golang环境变量

# set golang environment vars
export GOROOT=/usr/local/go

# set multiple gopaths seperated by ":"
export GOPATH=/var/www/go_projects/gotest.domain2.com

export PATH=$GOPATH/bin:$GOROOT/bin:$PATH

# set PATH so it includes user's private bin directories
PATH="$HOME/bin:$HOME/.local/bin:$PATH"

Systemd守护程序文件

[Unit]
Description=GoTest Webserver

[Service]
Type=simple
WorkingDirectory=/var/www/go_projects/gotest.domain2.com
ExecStart=/var/www/go_projects/gotest.domain2.com/main #binary file

[Install]
WantedBy=multi-user.target

VirtualHost Conf

<VirtualHost *:80>
    ServerName gotest.domain.com
    DocumentRoot /var/www/go_projects/gotest.domain2.com

    <Directory /var/www/go_projects/gotest.domain2.com>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride All
                Order allow,deny
                allow from all
    </Directory>

转到文件

package main

import (
    "fmt"
    "log"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World %s!", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

遗憾的是http://gotest.domain2.com上的程序未执行。它列出了DocumentRoot

的内容

手动运行返回

admin@xyz:/var/www/go_projects/gotest.domain2.com$ ./main 
2018/02/18 15:52:58 listen tcp :8080: bind: address already in use

我缺少什么或部署方法主要是错误的? 干杯!

编辑: 正如Michael Ernst所建议的那样,我尝试改变端口/代理设置,结果如下:

http://gotest.domain2.com leads to 503 Service Unavailable

以下是sudo netstat -talpen

的结果
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      0          16367       1250/sshd       
tcp        0      0 0.0.0.0:25              0.0.0.0:*               LISTEN      0          473536      26340/master    
tcp        0      0 0.0.0.0:143             0.0.0.0:*               LISTEN      0          16604       1417/dovecot    
tcp        0      0 0.0.0.0:2000            0.0.0.0:*               LISTEN      5001       17289       1652/asterisk   
tcp        0     xx.xx.xx.xx:22       xx.xx.xx.xx:6126      ESTABLISHED 0          615988      13025/sshd: admin [
tcp6       0      0 :::22                   :::*                    LISTEN      0          16369       1250/sshd       
tcp6       0      0 :::25                   :::*                    LISTEN      0          473537      26340/master    
tcp6       0      0 :::3306                 :::*                    LISTEN      111        17564       1391/mysqld     
tcp6       0      0 :::143                  :::*                    LISTEN      0          16605       1417/dovecot    
tcp6       0      0 :::80                   :::*                    LISTEN      0          612412      12554/apache2   
tcp6       0      0 xx.xx.xx.xx:80       xx.xx.xx.xx:6128      FIN_WAIT2   0          0           -               
tcp6       0      0 xx.xx.xx.xx:80       xx.xx.xx.xx:6129      ESTABLISHED 33         615029      12561/apache2   

知道问题出在哪里?

1 个答案:

答案 0 :(得分:2)

至于配置apache:

您需要启动go应用程序并在apache配置中反向代理请求到端口8080(您编写的go守护进程监听)。 go应用程序需要始终运行,因此您可能希望在系统启动时启动它。与从apache调用的php不同,go应该以二进制文件的形式运行。

关于您的端口问题:

确保您的应用程序尚未启动,并且没有其他应用程序正在侦听端口8080.(您可以使用netstat -talpen查看)

编辑: 端口8080通常是http代理。是否有代理或其他应用程序在这一点上运行?

编辑: 你可以像这样配置你的apache:

<VirtualHost *:80> 
  ProxyPreserveHost On
  ProxyRequests Off
  ServerName www.example.com
  ServerAlias example.com
  ProxyPass / http://localhost:8080/
  ProxyPassReverse / http://localhost:8080/
</VirtualHost>

您可能还希望使go-application的端口可配置,以便在需要更改端口时不需要重新编译代码。您也可以绑定到localhost接口,这样,如果您没有配置防火墙,人们只能通过apache访问go应用程序而不能直接与go应用程序通信

// define the flag
port := flags.Int("port", 8080, "port to listen on")
// parse the flags
flags.Parse();
// here you might want to add code to make sure the port is valid.
// start webserver
log.Fatal(http.ListenAndServe("localhost:"+strconv.Atoi(*port), nil))