localhost 拒绝了我们的连接请求 vscode_移动办公——在iPad上运行VSCode

导语


越来越多的业务开始上云,现在的个人开发环境也有上云的趋势。利用VSCode的远程开发模式,很多开发者已经把代码和编译环境都配置在云服务器上,本地的笔记本只是一个接入端。而这个接入端不一定是电脑,也可以使iPad等更轻量的设备。


Code Server


到目前为止,微软还没有提供iPad版本的VSCode。幸运的是,有一个叫coderom的团队提供了一个code server,安装到Linux服务器上之后,可以通过浏览器打开VSCode,进而实现从iPad上远程开发的目的。
同时,coderom还提供了code server的docker镜像,配置起来更加简便。
所以你需要的资源包括:一台云服务器,一个域名(可选,但用域名会方便很多),一台配了键盘的iPad。


开箱即用的方式


云服务安装好docker之后,直接把code server的容器跑起来就可以了:

docker run -it -p 80:8080 
  -v "$PWD/code:/home/coder/project" 
  -u "$(id -u):$(id -g)" 
  -e PASSWORD='abde32c' 
  codercom/code-server:3.7.4

然后在iPad的浏览器上打开你的域名

74107cc1424be62508b89340bc7d8990.png

上面docker启动时时已经通过环境变量指定密码,如果不指定密码,code server会随机生成一个。输入密码,即可开始iPad编程之旅。

a438405649ff1efd7bf9ac8007cd5454.png

安全保障


从上面的截图右下角也可以看到,现在访问code server没有加密,很不安全。一个方式是用一个ssh客户端进行端口转发,然后iPad直接访问本地端口来访问code server。iPad的ssh客户端可以选择Terminus。于是,docker容器改成只监听本地端口:

docker run -it -p 127.0.0.1:8090:8080 
  -v "$PWD/code:/home/coder/project" 
  -u "$(id -u):$(id -g)" 
  -e PASSWORD='abde32c' 
  codercom/code-server:3.7.4

然后用Terminus做端口转发:

520cf5179d210dca035e56412036af8d.png

但是iPad一个应用不在前台时很容易被清理掉,然后端口转发就停止了。好在现在iPad可以多应用开启,只不过要挤占有限的屏幕空间,用起来并不畅快。

HTTPS


另一个方式是通过HTTPS访问。code server也自带了https选项,但这里我没有选择使用它。因为我觉得更合适的方式是各个模块各司其职,让code server专门负责vscode的事情,通过另一个程序来做HTTPS的请求转发。另外一个考虑是,自己来做HTTPS请求转发,可以灵活定制。可以考虑写一个golang程序来做HTTPS监听,并将请求转发到本地的8090端口。

提供HTTPS服务需要有证书,因为这里的HTTPS服务仅仅是自己访问,只需要用一个自签名证书就可以了。推荐的方式是先生成一个rootCA根证书,再用这个根证书颁发一个服务器证书server.key和server.crt。这样客户端只需要信任根证书,服务端证书就自动被信任,而且以后服务端再换证书,客户端也不用修改。注意下面的http://your.domain.com需要替换成你的真实域名。

# generate rootCA locally.
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -days 750 
    -subj "/C=US/L=CA/O=VSCode Server CA/CN=VSCode Server Root CA" 
    -key rootCA.key -out rootCA.crt
    
# generate server certificate and key.
openssl genrsa -out server.key 2048
openssl req -new -sha256 
    -key server.key 
    -subj "/C=US/ST=CA/O=VSCode Server/CN=your.domain.com" 
    -out server.csr
openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -days 365 -sha256 
    -extensions SAN 
    -extfile <(cat /etc/ssl/openssl.cnf 
        <(printf "n[SAN]nsubjectAltName = DNS:your.domain.comnextendedKeyUsage = serverAuth")) 
    -in server.csr -out server.crt

服务器上需要rootCA.crt、server.key、server.crt,iPad需要rootCA.crt,rootCA.key应该仅保存在你的个人机器上。然后再实现一个golang的HTTPS服务器:

package main

import (
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io/ioutil"
    "net/http"
    "net/http/httputil"
    "net/url"
    "time"
)

func main() {
    codeServer, _ := url.Parse("http://localhost:8090/")
    codeServerDirector := func(req *http.Request) {
        req.Header.Add("X-Forwarded-Host", req.Host)
        req.Header.Add("X-Origin-Host", codeServer.Host)
        req.URL.Scheme = "http"
        req.URL.Host = codeServer.Host
    }
    codeServerProxy := &httputil.ReverseProxy{Director: codeServerDirector}

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Printf("proxy receive request from: %v at: %vn", r.RemoteAddr, time.Now())
        codeServerProxy.ServeHTTP(w, r)
    })

    certificate, err := tls.LoadX509KeyPair("../cert/server.crt", "../cert/server.key")
    if err != nil {
        fmt.Printf("load certificate fail: %vn", err)
        return
    }

    certPool := x509.NewCertPool()
    ca, err := ioutil.ReadFile("../cert/rootCA.crt")
    if err != nil {
        fmt.Printf("read ca file fail:%vn", err)
        return
    }
    if ok := certPool.AppendCertsFromPEM(ca); !ok {
        fmt.Println("failed to append certs")
        return
    }

    tlsconfig := &tls.Config{
        Certificates: []tls.Certificate{certificate},
        ClientAuth:   tls.NoClientCert, //tls.RequireAndVerifyClientCert,
        ClientCAs:    certPool,
    }

    s := &http.Server{
        Addr:      "0.0.0.0:443",
        Handler:   nil,
        TLSConfig: tlsconfig,
    }

    s.ListenAndServeTLS("", "")
}

这个golang的HTTPS服务器的功能非常单一,就是将所有请求转发给localhost:8090,即code server的端口。
iPad客户端需要信任rootCA.crt,然后直接打开https://your.domain.com,然后就可以到达之前输入密码的界面,进入编程环境。


还能更安全吗


注意现在只是客户端验证服务端的证书,服务端并没有验证客户端的证书,拦在攻击者前面的只有一个密码了。我们可以让服务端也校验客户端的证书,实现双向认证。先用之前的根证书颁发一个客户端证书:

# generate client certificate and key.
openssl genrsa -out client.key 2048
openssl req -new -sha256 
    -key client.key 
    -subj "/C=US/ST=CA/O=VSCode Client/CN=your.domain.com" 
    -out client.csr
openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -days 365 -sha256 
    -extensions SAN 
    -extfile <(cat /etc/ssl/openssl.cnf 
        <(printf "n[SAN]nsubjectAltName = DNS:your.domain.comnextendedKeyUsage = clientAuth")) 
    -in client.csr -out client.crt
openssl pkcs12 -export -out client.pfx -inkey client.key -in client.crt

然后整个打包发送到iPad上,安装为描述文件。注意我们已经信任了根证书,这个client.crt会自动被信任。HTTPS服务器的tls配置修改为要求客户端提供证书:

tlsconfig := &tls.Config{
    Certificates: []tls.Certificate{certificate},
    ClientAuth:   tls.RequireAndVerifyClientCert,
    ClientCAs:    certPool,
}

接着重新启动HTTPS服务器。
这种方式在Mac的Chrome验证通过,不过遗憾的是,iPad上的Chrome不认手动导入的客户端证书,Safari则仅在第一此连接时使用了客户端证书,后面的又不读取了,服务端会报tls: client didn't provide a certificate的错误。
所以目前暂时还只能使用单向HTTPS+密码的方式,为了更加安全,端口就不能长期打开了,仅在使用的时候把code server和HTTPS服务器打开。


总结


在iPad上用VSCode连接云服务器开发是可行的。通过配置独立于cod server 的HTTPS转发服务,可以加入更多的定制功能(比如自签名证书和客户端验证)。期待最终能实现iPad上的双向HTTPS验证方式使用VSCode。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值