独立应用程序的本地子域

时间:2017-03-11 02:18:57

标签: go proxy dns reverse-proxy

我有一个网站,由三个较小的“独立”子网站组成:

  • mysite的
    • 的index.html
    • 网站图示
    • 图像
    • 文档
      • 的index.html
      • CSS
      • IMG
      • JS​​
      • ...
    • 编辑
      • 的index.html
      • 图像
      • JS​​
      • SRC
      • ...

doc是使用Hugo :: A fast and modern static website engine创建的网站,editormxgraph Graphditor example;其余的文件是一个手工制作的登陆页面。

除了部署到任何Web服务器之外,我还希望将该站点作为“独立应用程序”进行分发。为此,我在go中写了这个非常简单的服务器:

package main

import (
  flag "github.com/ogier/pflag"
  "fmt"
  "net/http"
  "net/http/httputil"
  "os"
  "path/filepath"
)

var port = flag.IntP("port", "p", 80, "port to serve at")
var dir = flag.StringP("dir", "d", "./", "dir to serve from")
var verb = flag.BoolP("verbose", "v", false, "")

func init() {
  flag.Parse();
}

type justFilesFilesystem struct {
  fs http.FileSystem;
}
type neuteredReaddirFile struct {
  http.File
}

func (fs justFilesFilesystem) Open(name string) (http.File, error) {
  f, err := fs.fs.Open(name)
  if err != nil { return nil, err; }
  return neuteredReaddirFile{f}, nil
}

func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
  return nil, nil;
}

func loggingHandler(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        requestDump, err := httputil.DumpRequest(r, true)
        if err != nil { fmt.Println(err); }
        fmt.Println(string(requestDump))
        h.ServeHTTP(w, r)
    })
}

func main() {
  str, err := filepath.Abs(*dir)
  if err != nil { os.Exit(1); }
  fmt.Printf("Serving at port %d from dir %s\n\n",*port,str)

  http.ListenAndServe(fmt.Sprintf(":%d",*port), loggingHandler(http.FileServer(justFilesFilesystem{http.Dir(*dir)})))
}

因此,我可以运行simpleserver -d <path-to-mysite>并通过localhostlocalhost/doclocalhost/editor浏览网站。

然后,我想使用自定义(子)域,例如mylocal.appdoc.mylocal.appeditor.mylocal.app。所以,我在/etc/hosts文件中添加了以下行:127.0.0.1 mylocal.app。因此,我可以浏览mylocal.appmylocal.app/editormylocal.app/doc。此外,我可以使用不同的包将其更改为mylocal.appmylocal.app:<editor-port>mylocal.app:<doc-port>

但是,当我尝试使用子域时,它未正确解析,因此任何反向代理策略都不起作用。由于不支持通配符,我可以在/etc/hosts文件中添加其他条目,但我更愿意避免使用。

虽然,另一种解决方案是运行dnsmasq,但我希望将应用程序保持独立。我发现了一些等效的golang包。但是,我觉得支持很多我不需要的功能。

此外,由于我不需要解析任何IP,而是提供localhost的别名,我认为代理就足够了。这也更容易配置,因为用户只能配置浏览器,并且不需要进行系统范围的修改。

然而,来自用户的所有流量都会被我的应用“过滤”。它是否正确?如果是这样,您能否指出我以最干净的方式实施它的任何参考。我知道这是非常主观的,但我的意思是相对较短(比如10行代码)片段,以便用户可以轻松检查发生了什么。

修改

我想使用类似的东西:

func main() {
    mymux := http.NewServeMux()
    mymux.HandleFunc("*.mylocal.app", myHandler)
    mymux.HandleFunc("*", <systemDefaultHandler>)
    http.ListenAndServe(":8080", mymux)
}

func main() {
    mymux := http.NewServeMux()
    mymux.HandleFunc("editor.mylocal.app", editorHandler)
    mymux.HandleFunc("doc.mylocal.app", docHandler)
    mymux.HandleFunc("*.mylocal.app", rootHandler)
    mymux.HandleFunc("*", <systemDefaultHandler>)
    http.ListenAndServe(":8080", mymux)
}

这些只是片段。一个完整的例子是this,在@ Steve101的评论中引用了它。

但是,现在,我不知道 systemDefaultHandler 是什么。那里没有解决。

除此之外,@ faraz建议使用goproxy。我认为HTTP/HTTPS transparent proxy是我正在寻找的默认处理程序。但是,使用一个包来做那件事对我来说似乎太过分了。我可以使用内置资源实现相同的功能吗?

2 个答案:

答案 0 :(得分:4)

不幸的是,通过Go,没有简单的方法可以做到这一点。您需要像dnsmasq一样拦截系统的DNS请求,并且这不可避免地需要对系统DNS配置进行一些修改(/etc/resolv.conf在Linux中,/etc/resolver在Mac或防火墙规则上)将DNS请求路由到您的应用程序。使用DNS有一个缺点,你需要在你的应用程序中构建一个类似于HashBytes()的DNS服务器,这似乎不必要地复杂。

由于系统配置不可避免,我投票支持在启动时或在添加/删除目录时(通过pow.cx)更改hosts文件。)关闭时,您可以清除也添加了条目。

如果您希望将这些更改隔离到特定浏览器而不是进行系统范围的更改,您可以始终通过fsnotify之类的代理服务器运行您的应用程序并告诉您的浏览器使用该更改代理请求。例如,您可以通过Chrome首选项或设置--proxy-server标记

在Chrome中执行此操作
--proxy-server=<scheme>=<uri>[:<port>][;...] | <uri>[:<port>] | "direct://"

有关详细信息,请参阅goproxy

此外,如果您愿意使用浏览器配置,则可以根据需要使用Chrome's network settings docs来处理请求。

答案 1 :(得分:0)

只有在没有代理的情况下才能工作的解决方案是你为此注册域并使用通配符创建一个正常的dns条目到127.0.0.1,如* .myApp.suche.org。因此,任何解析ip的客户端都会获得127.0.0.1并在本地工作。这样,您无需管理员权限即可修改/ etc / hosts或等效项。 如果它应该在代理之后工作而不修改解析器(etc / hosts等),你可以提供一个wpad.dat(用于代理检测的Javascript),对你的域说,所有流量都是服务器,其余的流量是真正的代理。如果在您的服务器中提供此脚本,则脚本可以自动包含默认的真实代理。