我们在浏览器地址栏输入localhost + 端口 就可以在本机测试自己做的网站,但是如果想把服务暴露在公网,让别人访问url就能访问,则需要更多的配置。常见的方法有两个,Nginx和使用内网穿透。

先说一下结论,Nginx比较适合部署在云服务器,而在自己家里的小服务器部署的服务更适合用内网穿透。一般云服务器都有公网IP且443端口是开放的,配置好之后我们就可以直接输入域名访问了。假设你的服务在家里,家里网络的HTTP 80和HTTPS 443端口一般是被运营商屏蔽了的,目的基本上除了安全就是防止用户因为商业用途私自搭建网站。

解决的办法就是不用443端口了,使用一个别的端口然后Nginx再转发到443端口,那么访问服务的时候就得加上新的端口,比如yourdomain.com:4433,但是我个人感觉不是很优雅。第二个办法就是使用内网穿透,常见的解决方案有Cloudflared。

Nginx

使用80/443端口

  • 首先创建一个新的文件夹,假设就放在~下,那么目录结构为

    ~
    ├── nginx
    │   └── docker-compose.yml
    └── service1
    │   ├── docker-compose.yml
    │   └── volume
    └── service2
        ├── docker-compose.yml
        └── volume
    
  • 编辑Nginx的docker-compose.yml,这里我们使用了Let's Encrypt去自动签发HTTPS证书。

    services:
      nginx-proxy:
        image: jwilder/nginx-proxy
        container_name: nginx-proxy
        restart: unless-stopped
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - /var/run/docker.sock:/tmp/docker.sock:ro
          - ./certs:/etc/nginx/certs:ro
          - ./vhost.d:/etc/nginx/vhost.d
          - ./html:/usr/share/nginx/html
          - ./conf.d:/etc/nginx/conf.d
        networks:
          - nginx
    
      letsencrypt:
        image: jrcs/letsencrypt-nginx-proxy-companion
        container_name: nginx-letsencrypt
        restart: unless-stopped
        environment:
          - NGINX_PROXY_CONTAINER=nginx-proxy
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - ./certs:/etc/nginx/certs
          - ./vhost.d:/etc/nginx/vhost.d
          - ./html:/usr/share/nginx/html
        depends_on:
          - nginx-proxy
        networks:
          - nginx
    
    networks:
      nginx:
        external: true
    
  • 创建一个docker网络,名叫nginx

    docker network create nginx
    
  • 启动容器

    docker compose up -d
    

    这样Nginx和Let’s Encrypt就启动好了,后面当我们暴露服务(这篇文章讲述了我使用这个Nginx来配置Vaultwarden服务)的时候,就可以直接使用Nginx做反向代理了。

使用其他端口

只需要将ports改成其他的端口,比如

ports:
  - "8080:80"
  - "8443:443"

注意事项:Let’s Encrypt仍然需要80端口用于更新证书,而且这个是无法修改的,所以如果这两个端口被封掉,可以进行访问,但是只能手动更新证书了。

Cloudflared

Cloudflared是Cloudflared推出的内网穿透客户端,基本原理就是本地安装一个客户端,能和Cloudflare的服务器通信,这样就形成了一条隧道,当用户访问我们站点的时候,Cloudflare先接收,然后再把请求转发给miniPC,从而实现公网访问。

使用这种方法我们甚至不需要公网IP,也不用开端口,Cloudflare能帮你做一些基本的防护。但是缺点是访问会受到Cloudflare的限制,国内访问可能会比较慢,以及需要一个域名。

Cloudflare配置

  • 有多种方式配置cloudflared,我这里使用的是token模式,即所有的配置都在cloudflare云端,本地只要保留这个token就可以连接上这个tunnel,这样本地的cloudflared也可以使用docker安装,将来假设如果要换设备只需要记住这个token即可,非常方便

  • 我们要去Cloudflare官网获取凭证,在Cloudflare开启Zero Trust,选择免费版即可

  • Network → Tunnels → Add a tunnel

    Add a tunnel

  • Tunnel Type选择Cloudflared

    Cloudflared

  • 跟着配置一步一步走,在Install一栏我们选择Docker,可以看到后面的Token,需要保管好这个token

  • 然后是添加Public Hostname,这个hostname就是你要暴露服务的hostname,假设我在miniPC上启动一个AList服务,AList使用的端口为5244,你希望访问alist.example.com就访问到这个服务,就应该这么填写

    Subdomain: alist
    Domain: example.com
    Type: HTTP
    URL: localhost:5244
    

    但是如果你是Docker部署的(建议),那么可以要这么配置,意思是去访问Docker容器的端口(假设容器名叫alist)

    Subdomain: alist
    Domain: example.com
    Type: HTTP
    URL: alist:5244
    
  • 这样云端就算是完成了,我们来配置miniPC端

MiniPC

  • 创建一个新的文件夹,就叫cloudflared,可以和其他的服务并列

    ~
    ├── cloudflared
    │   └── docker-compose.yml
    └── service1
    │   ├── docker-compose.yml
    │   └── volume
    └── service2
        ├── docker-compose.yml
        └── volume
    
  • 创建docker-compose.yml,token就填写刚才的token,这样我们甚至不用挂载本地卷

    services:
      cloudflared:
        image: cloudflare/cloudflared:latest
        container_name: cloudflared
        restart: unless-stopped
        command: tunnel --no-autoupdate run --token [YOUR TOKEN]
        networks:
          - cloudflared
    
    networks:
      cloudflared:
        external: true
    
  • 创建docker网络就叫cloudflared

    docker network create cloudflared
    
  • 这样就算是配置完了,我们后面如果需要添加服务就新建一个域名到cloudflared即可

其他方法

还有些协议就就不一一尝试了,原理基本上都和上面两个相同:

  • Caddy:方向代理
  • Traefik:反向代理
  • FRP:内网穿透,分为FRPC和FRPS,在VPS上部署FRPS,miniPC或者软路由部署FRPC
  • ZeroTire:内网穿透
  • Wireguard:非常轻量的VPN,可以先使用VPN连接自己家的内网,然后再访问
  • Tailscale:基于Wireguard的VPN