【搭建个人网站】借助内网穿透+云服务器中转

前言

在个人的项目部署中,我们常常面临以下挑战:

  • 业务应用数量众多,全部部署至云服务器成本高昂
  • 需要在本地环境运行服务,但缺乏固定公网 IP
  • 希望使用自定义域名提供专业服务访问体验

针对这些痛点,我们采用云服务器中转 + 内网穿透的方案:

  • 利用云服务商提供的 ECS 实例与公网 IP 作为流量入口
  • 通过 FRP 工具建立安全的内网穿透通道
  • 将实际业务服务部署在内网环境,享受本地部署的灵活性与成本优势
  • 结合自有域名,为用户提供统一的专业访问入口

一、内网穿透

1. 准备一台云服务器

先去阿里云的高校计划白嫖300元优惠券,开通一年2c2g的ECS服务器选择按量计费的IP服务。

或者其他腾讯云、京东云厂商的便宜服务器都行。

2. 云服务器安装frp工具

基本原理:

  • 公网服务器 (云服务器) :具有固定公网IP,运行 frp 的服务端 frps
  • 内网服务器/设备 :位于 NAT 或防火墙后,运行 frp 的客户端 frpc
  • 通信流程frpc 主动连接 frps 建立控制通道,当外部用户访问 frps 的某个端口时,frps 会将请求通过已建立的通道转发给 frpc,再由 frpc 转发给内网的特定服务。

接下来创建完实例登录控制台,打开远程控制界面。安装frp工具

下载 frp :从 frp GitHub Releases 下载对应平台的二进制文件

上传并解压 frp

复制代码
tar -xzf frp_0.52.3_linux_amd64.tar.gz
cd frp_0.52.3_linux_amd64

编辑服务端配置文件 frps.ini

复制代码
[common]
# frp 服务端监听的端口,客户端通过此端口连接
bind_port = 7000

# 可选:Web 管理界面端口
dashboard_port = 7500
# 管理界面的用户名和密码
dashboard_user = admin
dashboard_pwd = password

# 可选:身份验证令牌,建议设置以增强安全性
token = yourtoken

# 可选:设置最大并发连接数
max_pool_count = 100
# HTTP 和 HTTPS 代理端口
vhost_http_port = 80
vhost_https_port = 443

启动 frp 服务端

复制代码
./frps -c frps.ini

设置开机自启 (Systemd)

创建 systemd 服务文件:sudo vim /etc/systemd/system/frps.service

ExecStart的路径要修改成你自己的路径

复制代码
[Unit]
Description=Frp Server Service
After=network.target

[Service]
Type=simple
User=nobody
Restart=on-failure
RestartSec=5s
ExecStart=/path/to/frps -c /path/to/frps.ini

[Install]
WantedBy=multi-user.target

启用服务

复制代码
sudo systemctl daemon-reload
sudo systemctl enable frps
sudo systemctl start frps

开启防火墙,在控制台的安全组里面开启防火墙放行(如果安装了宝塔面板,宝塔里面也要开启)

3. 内网服务器配置frp

上传并解压 frp (同服务端步骤)

编辑客户端配置文件 frpc.ini

复制代码
[common]
server_addr = 101.205.73.227
server_port = 7000
token = yourtoken

# 所有 HTTP 流量都代理到 Nginx
[web-http]
type = http
local_ip = 127.0.0.1
local_port = 80
custom_domains = zs4m.cn,www.zs4m.cn,api.zs4m.cn

# 所有 HTTPS 流量都代理到 Nginx  
[web-https]
type = https
local_ip = 127.0.0.1
local_port = 443
custom_domains = zs4m.cn,www.zs4m.cn,api.zs4m.cn

# SSH 服务
[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000

创建服务文件:sudo vim /etc/systemd/system/frpc.service

复制代码
[Unit]
Description=Frp Client Service
After=network.target

[Service]
Type=simple
User=nobody
Restart=on-failure
RestartSec=5s
ExecStart=/path/to/frpc -c /path/to/frpc.ini

[Install]
WantedBy=multi-user.target

启用服务:

复制代码
sudo systemctl daemon-reload
sudo systemctl enable frpc
sudo systemctl start frpc

访问 Dashboardhttp://x.x.x.x:7500 (使用设置的用户名密码登录)

HTTP 服务测试:访问域名需要先配置好DNS解析和nginx

复制代码
curl http://zs4m.cn

二、域名解析

1. 购买一个域名并且备案

直接搜索域名,各个厂商都有提供,随机挑选一个就可,1块钱一年

在哪个云服务商购买的服务器 ,就在哪个服务商进行备案阿里备案

配置域名解析:

获取SSL证书,各个云厂商也有提供。子域名需要认证多个,点击下载key和pem

2. nginx代理

在云服务器上我们配置了80,443端口的http流量都会转到内网服务器上,内网服务器再根据域名接收,不同的子域名对应不同的端口,需要nginx来做ssl解密和转发。这里使用docker来安装运行,后续所有服务也运行在docker上。

1) 安装docker

复制代码
curl -fsSL https://get.docker.com | bash
sudo systemctl enable docker
sudo systemctl start docker

配置代理:

复制代码
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://mirror.ccs.tencentyun.com",
    "https://hub-mirror.c.163.com",
    "https://registry.docker-cn.com"
  ]
}
EOF

重启docker:

复制代码
sudo systemctl daemon-reload
sudo systemctl restart docker

2) 安装portainer

Portainer 是一个轻量级、开源的容器管理图形化界面,专门用于管理 Docker 和 Kubernetes 环境。它的核心理念是让容器管理变得简单,即使是对命令行不熟悉的开发人员或运维人员也能轻松上手。

复制代码
docker pull portainer/portainer
docker run -d --restart=always --name portainer -p 9009:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer

访问:http://ip:9009

3)安装nginx

创建网站目录和文件

复制代码
# 创建项目目录
mkdir -p ~/docker/nginx/zs4m.cn/html
cd ~/docker/nginx/zs4m.cn

# 创建网站首页
cat > html/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
    <title>欢迎访问 zs4m.cn</title>
    <meta charset="utf-8">
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .container { max-width: 800px; margin: 0 auto; }
        .header { background: #f5f5f5; padding: 20px; border-radius: 5px; }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🚀 欢迎访问 zs4m.cn!</h1>
            <p>网站运行在内网服务器的 Docker 容器中</p>
            <p>通过云服务器 frp 中转访问</p>
        </div>
        <div>
            <h2>系统信息</h2>
            <p>服务器时间: <span id="time"></span></p>
            <p>访问者IP: <span id="ip"></span></p>
        </div>
    </div>
    <script>
        document.getElementById('time').textContent = new Date().toLocaleString();
        // 简单的IP显示(实际需要后端支持)
        fetch('https://api.ipify.org?format=json')
            .then(response => response.json())
            .then(data => document.getElementById('ip').textContent = data.ip)
            .catch(() => document.getElementById('ip').textContent = '无法获取');
    </script>
</body>
</html>
EOF

创建 Nginx 配置文件:

复制代码
mkdir -p conf

default.conf

复制代码
# 主站点 HTTP 重定向
server {
    listen 80;
    server_name zs4m.cn www.zs4m.cn;
    return 301 https://$server_name$request_uri;
}

# 主站点 HTTPS
server {
    listen 443 ssl;
    server_name zs4m.cn www.zs4m.cn;
    
    client_max_body_size 100M;
    
    # SSL 证书配置
    ssl_certificate /etc/nginx/ssl/zs4m.cn.crt;
    ssl_certificate_key /etc/nginx/ssl/zs4m.cn.key;
    
    # SSL 安全配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # 安全头
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;

    # 代理到前端服务
    location / {
        proxy_pass http://cheeseai-web:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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 X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
    }

    # 健康检查
    location /health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }

    # 禁止访问隐藏文件
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

# API 站点 HTTP 重定向
server {
    listen 80;
    server_name api.zs4m.cn;
    return 301 https://$server_name$request_uri;
}

# API 站点 HTTPS
server {
    listen 443 ssl;
    server_name api.zs4m.cn;
    
    client_max_body_size 100M;
    
    # 使用相同的 SSL 证书
    ssl_certificate /etc/nginx/ssl/api.zs4m.cn.crt;
    ssl_certificate_key /etc/nginx/ssl/api.zs4m.cn.key;
    
    # SSL 安全配置(与主站相同)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # 安全头
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;

    # 代理到 API 服务
    location / {
        proxy_pass http://192.168.0.46:8090;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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 X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        
        # API 特定的超时设置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # API 健康检查
    location /health {
        proxy_pass http://192.168.0.46:8090/health;
        proxy_set_header Host $host;
        access_log off;
    }

    # 禁止访问隐藏文件
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

创建主配置文件

复制代码
# 创建主配置文件
cat > conf/nginx.conf << 'EOF'
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    tcp_nopush on;
    keepalive_timeout 65;
    gzip on;

    # 包含虚拟主机配置
    include /etc/nginx/conf.d/*.conf;
}
EOF

使用docker部署nginx

复制代码
cd /home/vvv/docs/dev-ops/nginx

cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  nginx:
    image: nginx:alpine
    container_name: nginx_zs4m
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"  # 新增 HTTPS 端口映射
    volumes:
      - ./html:/usr/share/nginx/html
      - ./conf/nginx.conf:/etc/nginx/nginx.conf
      - ./conf/default.conf:/etc/nginx/conf.d/default.conf
      - ./logs:/var/log/nginx
      - ./cache:/var/cache/nginx
      - ./ssl:/etc/nginx/ssl  # 挂载 SSL 证书目录
    networks:
      - dev-ops_my-network

networks:
  dev-ops_my-network:
    external: true
    name: dev-ops_my-network
EOF

启动

复制代码
# 在项目目录下启动服务
cd ~/docker/nginx/zs4m.cn
docker-compose up -d

# 检查容器状态
docker ps
docker logs nginx_zs4m

# 测试本地访问
curl http://localhost

添加ssl配置,在ssl目录下面上传从云服务器证书管理下载的key和pem,将pem重命名为crt后缀

复制代码
# 创建 SSL 配置目录
mkdir -p ssl

三、web服务

1. docker运行

前端服务已经准备好,直接build

复制代码
docker build --platform linux/amd64  -t mumu/cheeseai-web:1.0 .
# 停止并重新启动
docker-compose down
docker-compose up -d

# 检查状态
docker-compose ps

# 查看日志
docker logs nginx_zs4m

services:
  ai-agent-station-front:
    image: mumu/cheeseai-agent-front:1.0
    container_name: ai-agent-station-front-app
    ports:
      - "3002:3002"
    restart: unless-stopped
    networks:
      - my-network
    environment:
      - NODE_ENV=production
      - NEXT_PUBLIC_API_HOST_URL=https://api.zs4m.cn
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://localhost:3002" ]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

2. 访问服务

当用户在浏览器访问 https://zs4m.cn 时,完整的请求处理流程如下:

HTTPS 请求接收

用户浏览器向云服务器 443 端口发起 HTTPS 请求

FRP 服务端转发

云服务器上的 FRP 服务端(frps)接收请求,通过已建立的隧道将请求转发至内网服务器

FRP 客户端处理

内网服务器上的 FRP 客户端(frpc)接收转发来的请求

Nginx 反向代理

FRP 客户端将请求发送至本地 Nginx 服务的 443 端口,Nginx 作为反向代理将请求转发至实际的前端服务端口 3002

前端页面渲染

前端服务处理请求并返回页面内容,最终在用户浏览器中完成渲染展示

相关推荐
摘星编程1 小时前
openGauss 快速上手:CentOS 环境下单机部署完整指南
linux·运维·centos
大喵桑丶6 小时前
中间件快速部署(Nginx,Keepalived)
运维·nginx·中间件
hanyi_qwe7 小时前
文本三剑客--awk
linux·运维·服务器
liu****7 小时前
27.epoll(三)
服务器·开发语言·网络·tcp/ip·udp
Caven777 小时前
【Linux 技巧】如何在登录时自动激活 Conda Base 环境
linux·运维·conda
凌寒118 小时前
Linux(Debian)安装、卸载 MySQL
linux·运维·mysql·debian
云飞云共享云桌面8 小时前
如何降低非标自动化工厂的研发软件采购成本
运维·服务器·网络·数据库·性能优化·自动化
七七墨染8 小时前
DotMemory系列:5. 如何实现自动化抓取和应用自托管
运维·c#·自动化
泰克教育官方账号8 小时前
泰涨知识 | 什么是自动化巡检?
运维·服务器·数据库
怀旧,9 小时前
【Linux系统编程】7. 进程的概念(上)
linux·运维·服务器