golang 编译备忘

这篇文章记录 golang 编译的一些知识备忘。

一、背景

go中没有项目的说法,只有包, 其中有两个重要的路径,GOROOTGOPATH

  • GOROOT:Go的安装目录,(类似于java的JDK)
  • GOPATH:GOPATH 是我们的工作空间,保存go项目代码和第三方依赖包

我们可以使用 go env 查看相关设置信息:

image-20210428162240487

二、历史

1. GOPATH

使用 GOPATH 时,GO 会在以下目录中搜索包:

  1. GOROOT/src:该目录保存了Go标准库代码。
  2. GOPATH/src:该目录保存了应用自身的代码和第三方依赖的代码。

程序中引入包时,Go会先去 GOROOT的scr目录 中查找,然后在 GOPATH的src目录 找,如果该目录不存在,会报错找不到package。

现在已不再推荐使用 GOPATH 来构建应用了。

2. vendor

Vendor 目录是 Golang 从 1.5 版本开始引入的,为项目开发提供了一种离线保存第三方依赖包的方法。

1.5 版本需要手动设置环境变量 GO15VENDOREXPERIMENT=1

在执行 go buildgo run 命令时,会按照以下顺序去查找包:

  • 当前包下的 vendor 目录
  • 向上级目录查找,直到找到 src 下的 vendor 目录
  • 在 GOROOT 目录下查找
  • 在 GOPATH 下面查找依赖包

在发布 1.6 版本时,该环境变量的值已经默认设置为 1 了,该值可以使用 go env 命令查看。

在发布 1.7 版本时,已去掉该环境变量,默认开启 vendor 特性。

3. vendor管理工具混战

主要是一下三个工具:

godep

godep 通过 godep save 把第三包的版本依赖信息记录在Godeps.json下,并且把第三包完整拷贝一份到vendor下面。通过对 Godeps.json 文件进行版本管理即可以管理整个项目的第三方包依赖信息。

govendor

govendor init之后会在根目录下生成一个vendor文件夹。只需要对vendor/vendor.json进行版本控制,即可对第三包依赖关系进行控制。

glide

glide 通过glide createglide init命令初始化第三方包管理,会在项目根目录下生成一个glide.yaml,这个文件记录用到的第三方包的依赖关系,支持编辑修改。 glide通过glide install, 会把所有缺少的第三方包都下载到vendor文件夹下,并且会在glide.yaml中添加所有依赖的第三方包名称,在glide.lock文件中记录具体的版本管理信息。

4. module

2018年 8 月, Go 发布了 1.11版本,引入Module功能,新增了一组go mod命令,可以通过go help mod查看使用帮助,目前一共有8个子命令:

image-20210428183831784

从 Go 1.13 版本开始,go module 是Go语言默认的依赖管理工具。

三、go module使用

1. 配置

GO111MODULE

设置环境变量 GO111MODULE=on ,就可以使用 go module 了:

  1. GO111MODULE=off 禁用模块支持,编译时会从GOPATHvendor文件夹中查找包。
  2. GO111MODULE=on 启用模块支持,编译时会忽略GOPATHvendor文件夹,只根据 go.mod下载依赖,将依赖下载至%GOPATH%/pkg/mod/ 目录下。
  3. GO111MODULE=auto,当项目在$GOPATH/src外且项目根目录有go.mod文件时,开启支持。

go module 管理依赖后会在项目根目录下生成两个文件go.modgo.sum

GOPROXY

Go1.13 之后 GOPROXY 默认值为https://proxy.golang.org,在国内无法访问,要设置成国内的代理地址,我是用这个域名:

export GOPROXY=https://goproxy.cn
go mod 命令
go mod download    下载依赖的module到本地cache(默认为$GOPATH/pkg/mod目录)
go mod edit        编辑go.mod文件
go mod graph       打印模块依赖图
go mod init        初始化当前文件夹, 创建go.mod文件
go mod tidy        增加缺少的module,删除无用的module
go mod vendor      将依赖复制到vendor下
go mod verify      校验依赖
go mod why         解释为什么需要依赖
go.mod 文件

依赖信息大致如下:

image-20210428192727148

  • module用来定义包名
  • require用来定义依赖包及版本
  • indirect表示间接引用

在国内访问 golang.org/x 的各个包都需要翻墙,我们可以在 go.mod 中使用 replace 替换成 github 上对应的库:

replace (
    golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac => github.com/golang/crypto v0.0.0-20180820150726-614d502a4dac
    golang.org/x/net v0.0.0-20180821023952-922f4815f713 => github.com/golang/net v0.0.0-20180826012351-8a410e7b638d
    golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0
)
go get

在项目中执行go get命令可以下载依赖包,并且还可以指定下载的版本。

  1. 运行go get -u 将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号)
  2. 运行go get -u=patch将会升级到最新的修订版本
  3. 运行go get package@version将会升级到指定的版本号version

如果下载所有依赖可以使用go mod download命令。

go mod vendor

go mod vendor 会复制modules下载到vendor中, 只会下载你代码中引用的库,而不是 go.mod 中定义全部的module。用在 module 和 go vendor 混用的情况。

2. 初始化

我这边用 cobra 创建了个简单的项目,参考另一篇文章《golang Cobra 包介绍》

image-20210428155039659

对其做 module 初始化:

$ go mod init appname // 初始化当前文件夹, 创建go.mod文件
$ go mod tidy // 增加缺少的module,删除无用的module

使用 go mod init 要带上package的名字,比如我这里用了appname,这样当其它应用引用包时,就可以直接引用了。

image-20210429111556570

image-20210428175101554

go mod init xxxx

3. 编译

go build

如果你还是选择使用 vendor 来进行编译,那么运行这个命令:

$ go mod vendor // 把原有 vendor 目录里的内容,reset成当前程序所需的依赖包,然后复制到原有vendor目录下
$ go build -mod=vendor // 使用 vendor 进行build

4. 查看包列表

go list // 当前目录引用的包
go list -m all // 本机引用的包

go help list // 查看go list 的详细说明

参考资料


golang Cobra 包简单使用

Cobra 是一个 Golang 包,提供了简单的接口来创建命令行程序。同时也很容易的生成应用程序和命令,cobra create appnamecobra add cmdname 等。

一、概念

cobra 中几个个重要的概念,分别是 commands、arguments 和 flags:

  • commands 代表行为
  • arguments 就是命令行参数(或者称为位置参数)
  • flags 代表对行为的改变(命令行选项)

二、初步使用

1. 安装

$ go get -u github.com/spf13/cobra/cobra

2. 创建应用

$ cobra init --pkg-name appname

image-20210428154327426

3. 增加命令

$ cobra add eula
$ cobra add kazuha

image-20210428155039659

这两条命令生成了两个相关文件。

4. 尝试使用

首先确定包名,我姑且设置为

kelu.org/apptest

对 import 做个修改。

image-20210429112413943

初始化 go mod:

go mod init kelu.org/apptest
go mod tidy

image-20210429112607233

编译

go build

在本目录下生成了 apptest 可执行文件,运行:

./apptest
./apptest eula
./apptest kazuha

image-20210429112731078

image-20210429113707028

5. 代码结构

对着几个子命令文件 var kazuhaCmd = &cobra.Command{ 以下的代码看下就能知道大致的开发套路了。

image-20210429113106610

每个命令的内容都相对简单:

image-20210429113254806

三、编码开发

命令行中选项(flags)和参数(arguments)的区别,以 ls 命令为例:

ls -alh kelu*
  • alh对应的是选项(flags),以 - 或 – 开头
  • kelu* 对应的是参数(arguments),一般参数在所有选项

0. 具体功能

Run: func(cmd *cobra.Command, args []string) {
    fmt.Println("cobra demo program") // 在这里实现
},

1. 添加选项(flags)

根据选项的作用范围,可以把选项分为两类:

  • persistent,对于一些全局性的选项,比较适合设置为 persistent 类型,比如控制输出的 verbose 选项:既可以设置给该 Command,又可以设置给该 Command 的子 Command。

    var Verbose bool
    rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
    
  • local,只能设置给指定的 Command。

    var Source string
    rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
    

2. 添加参数(arguments)

cobra 默认提供了一些验证方法:

  • NoArgs - 如果存在任何位置参数,该命令将报错
  • ArbitraryArgs - 该命令会接受任何位置参数
  • OnlyValidArgs - 如果有任何位置参数不在命令的 ValidArgs 字段中,该命令将报错
  • MinimumNArgs(int) - 至少要有 N 个位置参数,否则报错
  • MaximumNArgs(int) - 如果位置参数超过 N 个将报错
  • ExactArgs(int) - 必须有 N 个位置参数,否则报错
  • ExactValidArgs(int) 必须有 N 个位置参数,且都在命令的 ValidArgs 字段中,否则报错
  • RangeArgs(min, max) - 如果位置参数的个数不在区间 min 和 max 之中,报错
var cmdTimes = &cobra.Command{
    Use: …
    Short: …
    Long: …
    Args: cobra.MinimumNArgs(1),
    Run: …
}

3. 帮助信息

cmd.SetHelpCommand(cmd *Command)
cmd.SetHelpFunc(f func(*Command, []string))
cmd.SetHelpTemplate(s string)

4. 提示信息

cmd.SetUsageFunc(f func(*Command) error)
cmd.SetUsageTemplate(s string)

5. prerun/postrun

var rootCmd = &cobra.Command{
    Use:   "cobrademo",
    Short: "sparkdev's cobra demo",
    Long: "the demo show how to use cobra package",
    PersistentPreRun: func(cmd *cobra.Command, args []string) {
        fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args)
    },
    PreRun: func(cmd *cobra.Command, args []string) {
        fmt.Printf("Inside rootCmd PreRun with args: %v\n", args)
    },
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Printf("cobra demo program, with args: %v\n", args)
    },
    PostRun: func(cmd *cobra.Command, args []string) {
        fmt.Printf("Inside rootCmd PostRun with args: %v\n", args)
    },
    PersistentPostRun: func(cmd *cobra.Command, args []string) {
        fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args)
    },
}

四、demo

package cmd

import (
	"fmt"
	"strings"

	"github.com/spf13/cobra"
)

// kazuhaCmd represents the kazuha command
var kazuhaCmd = &cobra.Command{
	Use:   "kazuha",
	Short: "A brief description of your command",
	Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("kazuha args:" + strings.Join(args, " "))
	},
}

var times int
var kaedeharaCmd = &cobra.Command{
	Use:   "kaedehara",
	Short: "kaedehara 楓原",
	Long:  `kaedehara 楓原万叶`,
	Args:  cobra.MinimumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		for i := 0; i < times; i++ {
			fmt.Println("kaedehara args:" + strings.Join(args, " "))
		}
	},
}

func init() {
	rootCmd.AddCommand(kazuhaCmd)
	kaedeharaCmd.Flags().IntVarP(&times, "times", "t", 1, "times loop for input")
	kazuhaCmd.AddCommand(kaedeharaCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// kazuhaCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// kazuhaCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

image-20210429145243364

参考资料


使用 dnspod 设置自定义解析

dnspod的专业版,可以自己定义某 IP 段去访问指定的主机服务,可以更细致的区分线路,或者屏蔽某个 DNS/区域用户访问网站。

这里记录如何查找本地网络 dns 的出口 IP。

  1. 首先确定本地的IP

    curl -s http://myip.ipip.net
    

    假如是 a.b.c.d

  2. 确定本地 ip 的出口IP段

    whois a.b.c.d
    

    你将得到这个IP的一些信息。查看 路由(route) 的信息,一般是一个b段或c段IP地址:

    a.b.0.0/16
    或者
    a.b.c.0/24
    
  3. 将这个IP段写入自定义线路配置

参考资料


vscode code server 配置 golang 和 php 开发环境

前几天更新了一篇blog,记录了怎么搭建 vscode code server。在使用场景中呢,我们不会使用一个没有语言环境的IDE,某些 IDE 的插件就是依赖于语言环境的。我日常使用 golang 和 php 比较多,这篇文章记录如何在 code server 中配置 golang 和 php 环境。

一、编译镜像

基于上一篇文章,得到了镜像 kelvinblood/code-server:base,在这个镜像的基础上继续编译新镜像。

有以下几个注意点:

  1. 基础镜像为先前编译的镜像 kelvinblood/code-server:base
  2. 配置了 golang 所需的环境变量 GOROOT 和 GOPATH,并打开了 GO111MODULE。
  3. 安装了 wget/ping/telnet 等常用的工具,方便定位问题。
  4. 安装了一些常用的 vscode 的 golang 插件。
  5. 安装了 go版本 1.16.3, php 版本7.1.5 和 最新版的composer。
FROM kelvinblood/code-server:base

ARG GOLANG_VERSION=1.16.3
ARG PHP_VERSION=7.1.5
ENV GOROOT /usr/local/go
ENV GOPATH /var/local/go
ENV PATH $PATH:$GOROOT/bin:$GOPATH/bin
ENV GO111MODULE on
ENV GOPROXY https://goproxy.cn

RUN \
 echo "**** install tools ****" && \
 apt-get update && \
 apt-get install -y \
	wget \
	iputils-ping \
	xinetd telnetd && \
 echo "**** install golang ****" && \
 GO_TGZ=go$(echo "$GOLANG_VERSION").linux-amd64.tar.gz && \
 wget https://golang.org/dl/${GO_TGZ} && \
 tar zxvf ${GO_TGZ} && \
 mv go /usr/local && \
 echo "**** go get for vscode ****" && \
 go get -v golang.org/x/tools/gopls && \
 go get -v github.com/ramya-rao-a/go-outline && \
# go get github.com/uudashr/gopkgs/cmd/gopkgs@latest && \
 go get -v github.com/cweill/gotests/gotests && \
 go get -v github.com/fatih/gomodifytags && \
 go get -v github.com/josharian/impl && \
 go get -v github.com/haya14busa/goplay/cmd/goplay && \
 go get -v github.com/go-delve/delve/cmd/dlv && \
 go get -v honnef.co/go/tools/cmd/staticcheck && \
 go get -v golang.org/x/tools/gopls && \
 echo "**** install php ****" && \
  apt-get -y install libssl-dev libcurl4-openssl-dev libbz2-dev libjpeg-dev libpng-dev libgmp-dev libicu-dev libmcrypt-dev freetds-dev libxslt-dev libcurl3-dev autoconf dpkg-dev file g++ gcc libc-dev make pkg-config re2c && \
  ln -s /usr/lib/x86_64-linux-gnu/libsybdb.a /usr/lib/libsybdb.a && \
  ln -s /usr/lib/x86_64-linux-gnu/libsybdb.so /usr/lib/libsybdb.so && \
  ln -s /usr/lib/x86_64-linux-gnu/libct.a /usr/lib/libct.a && \
  ln -s /usr/lib/x86_64-linux-gnu/libct.so /usr/lib/libct.so && \
  ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h && \
  ln -s /usr/include/x86_64-linux-gnu/curl /usr/include/curl && \
  PHP_TGZ=php-${PHP_VERSION}.tar.gz && \
  wget http://am1.php.net/distributions/${PHP_TGZ} && \
  tar -xzvf ${PHP_TGZ} && \
  cd php-${PHP_VERSION} && \
  ./configure --prefix /usr/share/php7 --enable-fpm --enable-mbstring --enable-zip --enable-calendar --enable-bcmath --enable-exif --enable-intl --enable-opcache --enable-shmop --enable-soap --enable-sockets --with-fpm-user=www-data --with-fpm-group=www-data --with-pcre-regex --with-kerberos --with-openssl --with-mcrypt --with-zlib --with-bz2 --with-curl --with-gd --with-jpeg-dir=/usr/include/jpeg8 --with-png-dir=/usr/include/libpng12 --with-gettext --with-gmp --with-mhash --with-xsl && \
  make clean && \
  make && make install && \
  make test && \
  make clean && \
  ln -s /usr/share/php7/sbin/php-fpm /usr/local/bin/php-fpm && \
  ln -s /usr/share/php7/bin/php /usr/local/bin/php && \
  cd .. && \
  curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer && \
 echo "**** clean up ****" && \
 pwd && \
 apt-get clean && \
 rm -rf \
	/tmp/* \
	/var/lib/apt/lists/* \
	/var/tmp/* \
        ${GO_TGZ} \
        ${PHP_TGZ}

docker build 需要比较长的时间,主要看机器性能和网络速度,需要一点耐心,快的也要10分钟,慢的大概要40分钟。

php 编译需要的内存比较高,如果只有1G内存的话最好把 swap 打开。

相应的 docker-compose.yml 文件和先前的没有差别。

二、常用插件

如下图所示,重要的就是这几个:

  • vim 是必不可少的
  • 简体汉化包
  • go包
  • laravel包
  • php Debug包

image-20210412141932034

三、主题和字体

左下角 -> 设置-> 颜色主题,不用看过多的主题,直奔Solarized Dark

image-20210412142238199

修改字体大小,默认14号字体太小了,改成18号

image-20210412142404907


go 命令备忘

这里简单记录几个常用的go命令。

go build

Go语言的编译速度非常快。Go 1.9 版本后默认利用Go语言的并发特性进行函数粒度的并发编译。

Go语言的程序编写基本以源码方式,无论是自己的代码还是第三方代码。

Go语言以 GOPATH 作为工作目录和一套完整的工程目录规则。因此 Go 语言中编译时无须像 C++ 一样配置各种包含路径、链接库地址等。

go build 命令主要用于编译代码,若有必要,会同时编译与之相关联的包。

go build 有很多种编译方法,如无参数编译、文件列表编译、指定包编译等,使用这些方法都可以输出可执行文件。

注意:需要编译的项目/文件一定要有 main package,且包含main函数,否则无法 build。

  1. go build 命令默认会编译当前目录下的所有 go 文件。如果没有main package,不会产生任何文件。

  2. 如果你只想编译其中某一个文件,可以在 go build 之后加上文件名,例如 go build a.go。

  3. 如果需要在 $GOPATH/bin 目录下生成相应的可执行文件,需要执行 go install 或者使用 go build -o </path/xxx>。

  4. go build 会忽略目录下以”_”或者”.”开头的go文件。

  5. 如果你的源代码针对不同的操作系统需要不同的处理,那么你可以根据不同的操作系统后缀来命名文件。例如有一个读取数组的程序,它对于不同的操作系统可能有如下几个源文件:

    array_linux.go 
    array_darwin.go 
    array_windows.go 
    array_freebsd.go
    

    go build 的时候会选择性地编译以系统名结尾的文件(Linux、Darwin、Windows、Freebsd)。例如Linux系统下面编译只会选择array_linux.go文件,其它系统命名后缀文件全部忽略。

go clean

用来移除当前源码包里面编译生成的文件

go get

用来动态获取远程代码包的,目前支持的有BitBucket、GitHub、Google Code和Launchpad。

这个命令在内部实际上分成了两步操作:

  1. 下载源码包
  2. 执行go install。

下载源码包的go工具会自动根据不同的域名调用不同的源码工具。

go install

go install 命令在内部实际上分成了两步操作:

  1. 生成结果文件(可执行文件或者.a包)
  2. 把结果移到 $GOPATH/pkg 或者 $GOPATH/bin

go test

自动读取源码目录下面名为 *_test.go 的文件,生成并运行测试用的可执行文件。

go doc

go doc 可以打印当前目录下文件的方法和类型定义

go doc
go doc -u xxxStruct
go doc http.Request

godoc

go get -v  golang.org/x/tools/cmd/godoc
godoc -http=:6060

以网页方式展现的Go文档,使得我们在不方便访问Go语言官方站点的情况下也可以查看Go语言文档,并且可以看自己代码的文档。

参考资料


搭建个人在线IDE —— vscode online

前年,微软在 Ignite 2019 大会上,正式发布了 「Visual Studio Online」。其中包含了微软托管的 WebVSCode,后来发布的 VSCode 1.40 支持开发者直接从 VSCode 的源代码编译出 WebVSCode

由于我目前开发环境众多,win/mac/Linux都有,虽然已经对代码做了容器化,还是需要重复下载代码,配置IDE环境,挺麻烦的。这篇文章简单记录我搭建在线IDE的过程。

安装

配置VSCode Online有几种方法:

  • 微软官方提供一个收费版本(含azure的服务器费用,捆绑销售),不推荐
  • 下载 VSCode 源代码,编译以后通过yarn web启动。配置难度大,不推荐
  • 通过 Code-Server 安装: https://code-server.dev/
  • 使用/修改现成的 docker 镜像:linuxserver/docker-code-server

我目前的方法是自行编译 linuxserver 提供的镜像。实际上只用linuxserver 的镜像已经足够了,没有特殊自定义要求的可以跳过这一部分。

这个文件是 code-server实际的启动命令,可以按需自定义修改:

#!/usr/bin/with-contenv bash

if [ -n "${PASSWORD}" ] || [ -n "${HASHED_PASSWORD}" ]; then
  AUTH="password"
else
  AUTH="none"
  echo "starting with no password"
fi

if [ -z ${PROXY_DOMAIN+x} ]; then
  PROXY_DOMAIN_ARG=""
else
  PROXY_DOMAIN_ARG="--proxy-domain=${PROXY_DOMAIN}"
fi

exec \
	s6-setuidgid abc \
		/usr/local/bin/code-server \
			--bind-addr 0.0.0.0:8443 \
			--user-data-dir /config/data \
			--extensions-dir /config/extensions \
			--disable-telemetry \
			--auth "${AUTH}" \
			"${PROXY_DOMAIN_ARG}" \
			/config/workspace

例如我将端口由 8443 改成了 80。

--bind-addr 0.0.0.0:80

修改 dockerfile 中的 expose 内容

EXPOSE 8443

改为

EXPOSE 80

在项目主目录进行编译:

docker build \
  --no-cache \
  --pull \
  -t kelvinblood/code-server:base .

运行

参考 https://github.com/linuxserver/docker-code-server 的帮助内容,我做了调整:

docker-compose.yml:

version: "2.1"
services:
  code-server:
    image: kelvinblood/code-server:base
    container_name: code-server
    network_mode: bridge
    environment:
      - PUID=0
      - PGID=0
      - TZ=Asia/Shanghai
      - PASSWORD=xxxx  #optional
#      - HASHED_PASSWORD= #optional
#      - SUDO_PASSWORD=abcd #optional
#      - SUDO_PASSWORD_HASH= #optional
      - PROXY_DOMAIN=xxx.kelu.org #optional
    volumes:
      - ./config:/config
      - /root/abc:/Workspace/abc
      - /root/xxx:/Workspace/xxx
#    ports:
#      - xxxx:80
    restart: unless-stopped

配置nginx

image-20210407170010631

在这一块我做多了几个安全认证,这几项都不是必须的,可以跳过,一个是使用https访问:

  ssl_certificate /etc/letsencrypt/live/code.kelu.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/code.kelu.org/privkey.pem;
  ssl_session_timeout 5m;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
  ssl_prefer_server_ciphers on;

一个是nginx密码

  auth_basic "Please input password";
  auth_basic_user_file /etc/nginx/passwd/goaccess;

一个是允许特定IP访问:

     satisfy any;
     allow xxx;
     allow xxx;
     deny all;

最后要注意配置 websocket 代理配置,最后两行:

  location / {
     satisfy any;
     allow 121.31.34.22;
     allow 61.51.94.34;
     deny all;

     proxy_pass http://code-server.bj1.local;
     proxy_read_timeout 300s;
     proxy_send_timeout 300s;

     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 Accept-Encoding gzip;

     proxy_set_header Upgrade $http_upgrade;
     proxy_set_header Connection "upgrade";
  }
}

界面预览

image-20210407170700847

装上自己需要的插件,就可以开始开发了。

image-20210407171100100

参考资料