模仿 vscode-server 把本地代码目录映射到外网


目录
  • vscode-server 效果,借助 ssh 、反向代理 的方式把本地代码映射到外网,通过 Web IDE 打开。

    概述

    vscode 推出了一个新的功能 —— vscode-server,可以把本地的代码映射到外网(vscode.dev),通过浏览器(Web IDE)修改和调试代码。

    用户PC 通过安全隧道与 vscode.dev 通信,连接成功后,用户将获得一个设备代码和 URL,你可以任意的可联网设备上打开这个URL 并验证 GitHub 帐户后,就可以通过vscode 的 web 版编辑你的PC上的代码。

    不足的是浏览器上使用时会有点卡顿,主要受到网速的影响,而且需要使用github账号登录,不太方便。

    操作步骤:准备一个github的账号,然后在 vscode UI 或者 code tunnel命令 生成一个外网url,访问这个url就可以在任意联网设备上通过浏览器浏览你本机的代码,如果需要调试需要安装一下vscode 插件。

    分析

    本地电脑 与 vscode.dev 连接时采用的安全隧道技术,再通过 vscode.dev 访问本地电脑的文件夹,具体的安全隧道技术细节比较复杂这里不展开,不过从实现的角度,还是有现成的技术可以作为解决方案。首先,为了方便和安全映射本地文件夹目录到容器;然后,把容器的webide、ssh端口映射到外网;最后,就可以在浏览器输入外网地址访问webide,或者 vscode 的remote ssh功能对本地代码进行修改。

    解决方案

    首先你需要准备 一台公网的服务器,以及这台服务器对应的公网ip 或者 域名。

    • 启动一个包含开发调试环境的 webide docker 容器,使用 SmartIDE 在本地代码目录下 运行 smartide start 即可

      创建一个容器,文件映射到你本地文件夹,不直接映射本地会比较安全,也简单很多,本地操作系统需要映射22会很折腾;另外用 SmartIDE 启动容器会方便很多,否则你还要自己写一个镜像,环境多了还要维护几个,干脆就不折腾了吧。

    • 通过 ssh远程转发 或者 ngrok内网穿透 的方式把容器的 SSH端口、WebIDE端口映射到外网
    • 通过浏览器打开外网地址打开代码窗口,或者 通过 VSCode 的 Remote Development (包含Remote SSH) 插件进行开发调试。

    准备一台VM

    比较推荐使用 azure 云,最好是选择 Ubuntu 系统,包管理更加方便,而且软件版本也比较新。

    创建容器

    SmartIDE 创建

    ## 进入到代码目录
    cd CODE_FOLDER
    
    ## 运行 smartide start
    ## 可以到模板库 https://gitee.com/smartide/smartide-templates.git 查看您需要的代码模板,即开发语言 和 WebIDE类型
    ## 比如,我是一个 golang 项目,需要使用VSCode 的 webide,脚本是 
    smartide start golang --type vscode 
    

    查看 SSH 和 WebIDE 对应的端口,如果命令行窗口关闭,也可以通过docker ps命令查看。

    整个过程不算太快,需要花大改2-3分钟;看到 “SmartIDE 启动完毕” 的字眼的时候可以关闭命令行,或者 ctrl + c 退出也不会有影响,应该容器已经安装到你 PC 的docker上了。

    直接使用 docker 创建

    相比smartide创建的容器,目测简单一些,但是实际还是有些麻烦,比如本地端口占用问题,具体的开发语言支持问题 等等,都可能需要自己再编排一下 Dockerfile,而 SmartIDE 把这些坑都踩过了。

    • webide 使用 theia,这个WebIDE的特点是扩展性强
    • 开放ssh服务,方便vscode remote ssh连接
    • 需要的开发环境,需要重新编排Dockerfile,这里暂时略过
    ## LOCAL_CODE_FOLDER 替换为本地代码文件夹路径
    docker run -it --restart always                  \
                         -p              8000:3000     \
                         -p              8022:22       \
                         -v     "LOCAL_CODE_FOLDER:/home/project" \
                         --name theia                  \
                         -d                            \
                                     brjapon/theia-arm64
    
    

    SSH 远程转发

    远程主机配置

    ## 首先登录 远程主机
    ssh remote_user@remote_host 
    
    ## 修改 “/etc/ssh/sshd_config” , GatewayPorts 运行网络链接端口,AllowTcpForwarding 允许tcp转发,详情 https://www.jianshu.com/p/e87bb207977c
    ## GatewayPorts yes
    ## AllowTcpForwarding yes
    vim /etc/ssh/sshd_config
    
    ## 复制本地 ~/.ssh 目录下的 id_rsa、id_rsa.pub 到远程主机的 ~/.ssh 目录下
    
    ## 重启服务 / 重启远程主机
    systemctl restart sshd
    

    远程转发

    ssh -N -R 0.0.0.0:remote-port:target-host:target-port  remote_user@remotehost
    

    例如:ssh -N -R 0.0.0.0:8022:0.0.0.0:6822 -R 0.0.0.0:6800:0.0.0.0:6900 root@test.com
    参考:https://wangdoc.com/ssh/port-forwarding#远程转发

    • remote_port 是你希望连接到远程主机的端口,如果是云(比如 Azure)上的主机需要打开这个端口
    • target-host 本地可以访问的目标 host
    • target-port 本地访问 target-host 使用的端口,比如上面SimpleHTTPServer的 8080
    • remote_user 是连接到远程主机的用户名
    • remote_host 是远程主机的地址

    内网穿透

    目前比较多人用的内网穿透工具有几个: NPS 支持tcp、udp,以及http、socket5代理,web管理端比较强大;FRP 高性能的反向代理,支持tcp、udp、http、https等;ngrok 知名度最高,1.7以后闭源,但有公网服务可以使用比较方便。
    建议使用FRP,NPS 的管理端太重没有必要,ngrok v1.7后闭源且私有化部署非常费劲(按照网上的办法部署了多次都是失败),建议大家避坑。

    ngrok

    以下直接使用 ngrok.com 官网的服务,国内的也有,但不好用。

    ## 官网 (https://dashboard.ngrok.com/get-started/setup) 注册账号,下载客户端;
    ## 进入 rgrok 命令行工具所在目录;
    ## 复制token,替换“ngrok_token” 
    ngrok config add-authtoken ngrok_token 
    ## 映射 本地端口 到外网,替换 contarner_binding_port 为本地端口
    ngrok tcp localhost:contarner_binding_port
    

    这种效果上最简单的,借助公网上的 ngrok 服务,直接映射出去,如图可以看到内网的文件夹中的内容已经完全映射到了外网,包括隐藏文件夹 bin、obj

    frp

    从 (releases)[https://github.com/fatedier/frp/releases] 下载操作系统对应的安装包

    ├── frpc              客户端命令行工具
    ├── frpc.ini          客户端配置文件
    ├── frpc_full.ini     客户端完整配置示例
    ├── frps              服务端命令行工具
    ├── frps.ini          服务端配置文件
    └── frps_full.ini     服务端完整配置示例
    

    服务端

    修改配置文件 frps.ini ,示例可以参考 frps_full.ini,完成后 通过 ./frps -c frps.ini 可以启动 server

    [common]
    bind_port = 8088
    # token 信息,客户端也要保持一致
    token=smartide666
    
    # dashboard,可以查看连接情况
    dashboard_addr = 0.0.0.0
    dashboard_port = 7500
    dashboard_user = admin
    dashboard_pwd = admin
    
    

    在 /lib/systemd/system/ 下创建 frps.service

    sudo vim /lib/systemd/system/frps.service
    

    录入以下内容

    [Unit]
    Description=frps daemon
    
    [Service]
    Type=simple
    #此处把 frps_folder_path 替换成 frps的实际安装目录
    ExecStart=frps_folder_path/frps -c frps_folder_path/frps.ini
    
    [Install]
    WantedBy=multi-user.target
    
    

    服务器自启动 / 启动

    # 自启动
    sudo systemctl enable frps
    
    # 启动
    sudo systemctl start frps
    

    客户端

    编辑 frpc.ini 文件

    [common]
    server_addr = test001.southeastasia.cloudapp.azure.com
    server_port = 8088
    token = smartide666
    
    [web]
    type = tcp
    local_ip = 127.0.0.1
    local_port = 6900
    remote_port = 6900
    
    [ssh]
    type = ssh
    local_ip = 127.0.0.1
    local_port = 6922
    remote_port = 6922
    

    启动 frpc,如果是 mac/linux 自动的方法可以参考 frp 服务端配置

    ./frpc -c ./frpc.ini
    

    效果如下