您正在查看: Other 分类下的文章

Docker部署OpenVPN实战指南 | Web可视化配置 | 完美接入多种组网方案

引言

​ 在现代互联网时代,数据安全、隐私保护和远程接入已成为企业与个人网络部署的核心需求。传统 VPN 解决方案在保障网络通信安全方面发挥了重要作用,而随着容器化技术的成熟,将 VPN 服务以 Docker 方式部署并结合 Web UI 管理,正成为自建网络服务的新趋势。

项目简介

GavinTan/openvpn 是一个基于Docker容器化部署的OpenVPN服务器项目,旨在通过直观的 Web 管理界面简化 VPN 管理。该解决方案提供对用户账户管理客户端管理证书管理服务器配置实时连接监控的集中控制,同时通过多因素身份验证和 LDAP 集成保持企业级安全性。


核心特性

1. 账号与权限管理

项目提供了完善的用户管理系统,支持本地账号和LDAP集成两种认证方式:

  • 默认管理员账号为admin/admin,首次登录后可修改密码
  • 支持模板导入创建多个VPN账号,每个账号可独立管理
  • VPN用户可以登录专属页面,自行下载配置文件、修改密码、设置MFA
  • 集成LDAP后可与企业现有的账号体系打通,实现统一认证

2. 证书与密钥管理

作为VPN的核心安全组件,证书管理功能设计得非常周到:

  • 一键生成客户端证书和配置文件
  • 支持证书的吊销和重新生成
  • 自动管理证书有效期,避免过期导致的连接问题

3. 多协议与IPv6支持

项目在网络协议支持方面非常全面:

  • 同时支持UDP和TCP协议,可根据网络环境灵活选择
  • 完整的IPv6支持,适应现代网络环境
  • 双栈配置,IPv4和IPv6可以同时工作
  • 注意:使用IPv6时需要Docker网络和客户端都开启相应支持

4. 企业级安全特性

安全性是VPN最核心的要求,项目在这方面做得很扎实:

  • 多因素认证(MFA):支持基于时间的一次性密码(TOTP),大幅提升账号安全性
  • LDAP集成:可与企业Active Directory或OpenLDAP集成
  • 固定IP分配:可为特定用户分配固定的VPN IP地址
  • 加密标准:参考业界最佳实践配置加密算法和密钥长度

5. 监控与日志

友好的监控功能让问题排查变得简单:

  • 连接历史记录,可查看每个用户的连接时间和时长
  • 在线用户列表,实时掌握VPN使用情况
  • 详细的日志记录,便于故障诊断
  • 支持在线查看和编辑server.conf配置文件

6. 灵活的网络配置

针对不同的使用场景,项目提供了灵活的网络配置选项:

  • 组网模式(默认):客户端只路由VPN内网流量,不影响正常上网
  • 网关模式:客户端所有流量都通过VPN,实现完全的网络控制
  • CCD支持:可为特定客户端定制路由和网络配置
  • 支持在Web界面直接修改OpenVPN配置,启用自动更新后即时生效

部署教程

环境准备

在开始部署前,请确保你的服务器满足以下要求:

  • 操作系统:Linux(推荐Ubuntu 20.04+或CentOS 7+)
  • Docker版本:20.10+
  • 网络:服务器需要有公网IP或可被客户端访问的网络地址

方式一:Docker Run 快速部署

这是最简单的部署方式,适合快速测试和小规模使用:

# 创建数据目录
mkdir-p~/openvpn-data

# 启动容器
dockerrun-d\
--nameopenvpn\
--cap-add=NET_ADMIN\
-p1194:1194/udp\
-p8833:8833\
-v~/openvpn-data:/data\
-v/etc/localtime:/etc/localtime:ro\
docker.1ms.run/yyxx/openvpn

参数说明:

  • --cap-add=NET_ADMIN:赋予容器网络管理权限,OpenVPN必需
  • -p 1194:1194/udp:映射VPN服务端口(UDP协议)
  • -p 8833:8833:映射Web管理界面端口
  • -v ~/openvpn-data:/data:持久化数据目录,包含配置、证书等重要文件
  • -v /etc/localtime:/etc/localtime:ro:同步系统时间,确保日志时间准确

方式二:Docker Compose 部署

对于生产环境,推荐使用Docker Compose,便于管理和维护:

1. 安装Docker Compose

# CentOS/RHEL
yum install -y docker-compose-plugin

# Ubuntu/Debian
apt install -y docker-compose-plugin

2. 创建docker-compose.yml文件

mkdir ~/openvpn&&cd~/openvpn
cat>docker-compose.yml<<'EOF'
services:
openvpn:
    image:docker.1ms.run/yyxx/openvpn
    container_name:openvpn
    restart:unless-stopped
    cap_add:
      -NET_ADMIN
    ports:
      -"1194:1194/udp"
      -"8833:8833"
    volumes:
      -./data:/data
      -/etc/localtime:/etc/localtime:ro
EOF

3. 启动服务

docker compose up -d

4. 查看日志

docker compose logs -f openvpn

IPv6 支持配置

如果你的网络环境支持IPv6,可以启用IPv6功能:

services:
  openvpn:
    image:docker.1ms.run/yyxx/openvpn
    container_name:openvpn
    restart:unless-stopped
    cap_add:
      -NET_ADMIN
    ports:
      -"1194:1194/udp"
      -"8833:8833"
    volumes:
      -./data:/data
      -/etc/localtime:/etc/localtime:ro
    sysctls:
      -net.ipv6.conf.default.disable_ipv6=0
      -net.ipv6.conf.all.forwarding=1

networks:
default:
    enable_ipv6:true

IPv6使用注意事项:

  • 需要在Web管理界面的系统设置中启用IPv6选项
  • 客户端和服务端的协议都要指定为udp6或tcp6
  • Docker网络必须启用IPv6支持
  • OpenVPN Connect客户端需要3.4.1或更高版本

初始化配置流程

服务启动后,按以下步骤完成初始化:

第一步:登录管理界面

  1. 浏览器访问 http://服务器IP:8833
  2. 使用默认账号登录:用户名admin,密码admin
  3. 登录后立即在系统设置中修改管理员密码

第二步:生成客户端配置

  1. 进入"管理" → "客户端"页面
  2. 点击"添加客户端",输入客户端名称、VPNServer及端口
  3. 下载生成的.ovpn配置文件

第三步:创建VPN账号

  1. 进入"管理" → "VPN账号"页面
  2. 点击"添加账号",设置用户名和密码
  3. 默认启用了账号验证,可根据需要关闭

第四步:客户端连接测试

  1. 在客户端设备上安装OpenVPN客户端软件,用第三步创建账号访问http://服务器IP:8833下载对应平台软件
  2. 导入第二步下载的配置文件
  3. 使用第三步创建的账号密码连接
  4. 连接成功后可在管理界面看到在线用户

LDAP集成配置

对于企业用户,可以集成LDAP实现统一认证:

  1. 在系统设置中启用LDAP认证
  2. 配置LDAP服务器参数:
    • OpenLDAP使用:uid
    • Windows AD使用:sAMAccountName
  3. LDAP_URL:LDAP服务器地址,如ldaps://ldap.example.com:636
  4. LDAP_USER_ATTRIBUTE:用户属性字段
  5. LDAP_USER_ATTR_IPADDR_NAME:用于存储固定IP的字段(可选)
  6. LDAP_USER_ATTR_CONFIG_NAME:用于存储客户端配置的字段(可选)

注意:启用LDAP后,本地VPN账号将不再工作,所有认证都通过LDAP进行。


常见问题排查

问题1: 容器启动失败

  • 检查是否赋予了NET_ADMIN权限
  • 确认端口1194和8833未被占用
  • 查看容器日志:docker logs openvpn

问题2: 客户端无法连接

  • 确认服务器防火墙放行了1194端口
  • 检查客户端配置文件中的服务器地址是否正确
  • 验证VPN账号是否启用

问题3: 连接后只能访问8833,无法访问其他服务

这是最常见的问题!原因是没有配置路由推送

解决方案:

  1. 检查路由是否已推送

在Web界面【管理】-->【配置文件】查看 server.conf 配置中是否有类似内容:

push "dhcp-option DNS 8.8.8.8"
push "route 10.0.12.0 255.255.252.0"
push "route 172.17.0.0 255.255.0.0"
push "route 10.100.100.0 255.255.255.0"
  1. 检查服务器IP转发
sysctl net.ipv4.ip_forward
# 应该返回: net.ipv4.ip_forward = 1
  1. 检查iptables规则
iptables -t nat -L -n
# 应该看到 MASQUERADE 规则
  1. 客户端重新连接

修改配置后,客户端必须断开重连才能获取新路由

问题4: 不知道该添加哪些路由

按需添加,不要一股脑全加!判断方法:

# 1. 查看服务器网卡信息
ip addr show

# 2. 确定你要访问的目标
# - 只访问服务器本机? → 只加服务器内网网段
# 云服务器内网路由
push "route 10.0.12.0 255.255.252.0"

# - 要访问ZeroTier设备? → 加ZeroTier网段
push "route 10.100.100.0 255.255.255.0"

# - 要访问Docker容器内部? → 加Docker网段
push "route 172.17.0.0 255.255.0.0"

# 3. 使用最小配置原则
# 先加最必要的,测试通过后再按需添加

问题5: 路由配置后还是无法访问

逐步排查:

# 1. 在客户端检查路由表
# Windows: route print
# Mac/Linux: netstat -rn

# 2. 测试连通性
ping 10.8.0.1        # 测试VPN网关
ping 10.0.12.12      # 测试服务器IP
traceroute 10.0.12.12 # 查看路由路径

# 3. 检查防火墙
# 确认服务器和客户端防火墙都允许相关流量

项目界面预览

管理后台主页

客户端管理

账号管理

系统设置页面

自助页面下载安装客户端

适用场景

1. 企业远程办公

  • 为员工提供安全的内网访问通道
  • 与企业AD/LDAP集成,实现统一账号管理
  • 通过MFA增强安全性
  • 管理员可以随时查看连接情况,掌控网络安全

2. 开发团队协作

对于需要访问开发环境的团队:

  • 为开发人员分配VPN账号,访问测试服务器
  • 固定IP功能方便配置白名单
  • 支持快速添加和删除用户,响应人员变动
  • 详细的连接日志便于审计

3. 多地办公组网

连锁企业或多分支机构可以:

  • 将各地办公网络通过VPN互联
  • 使用组网模式不影响员工正常上网
  • 集中管理所有分支的VPN接入
  • 支持大规模部署,批量生成配置

4. 个人隐私保护

对于注重网络隐私的个人用户:

  • 自建VPN服务器,避免使用商业VPN
  • 启用网关模式,所有流量加密传输
  • 通过MFA保护账号安全
  • 完全掌控数据,无需担心隐私泄露

5. 安全测试与渗透

网络安全从业者可以:

  • 搭建测试用VPN环境
  • 快速为团队成员分配临时账号
  • 灵活的网络配置满足各种测试场景
  • 详细日志方便分析测试结果

6. 家庭智能设备远程访问(实用场景)

这是最常见的个人使用场景:

需求: 外出时访问家里的NAS、监控、智能家居

架构方案:

手机(外网) → OpenVPN(云服务器) → ZeroTier/EasyTier → 家里设备

路由配置:

# OpenVPN配置
push "route 10.100.100.0 255.255.255.0"  # ZeroTier网段
# 家里的NAS、路由器、摄像头都在这个网段

实际效果:

  • 手机连上VPN后访问 http://10.244.244.5:5000 (家里NAS)
  • 访问 http://10.244.244.6:8080 (家里监控)
  • 不影响手机正常上网(微信、购物等不走VPN)

为什么不直接用ZeroTier?

  • ZeroTier手机客户端常驻后台,耗电高
  • OpenVPN用完就断,更省电
  • 灵活性更好,可以给朋友临时分配访问权限

相关链接


总结

​ 该项目是一款结合了 Docker 部署与 Web 管理 UI 的 OpenVPN 解决方案,既保留了 OpenVPN 强大的网络安全能力,又通过 Web 界面降低了部署和维护门槛。对于希望快速构建自有 VPN 平台或希望在内部网络中实现便捷远程访问管理的团队和个人开发者,该项目是一种高效实用的方案。

转载:https://mp.weixin.qq.com/s/FSMfjzZOr4TkI1o-OfjlSA

Nginx性能调优20条黄金法则:支撑10万并发的配置模板

一、概述

1.1 背景介绍

说实话,Nginx调优这事儿我踩过无数坑。记得2019年双11,我们电商平台流量暴涨,Nginx直接扛不住了,QPS从平时的2万飙升到8万,响应时间从50ms飙到了2秒,最后还是靠临时加机器扛过去的。那次事故之后,我花了大半年时间专门研究Nginx的性能极限,总结出了这20条黄金法则。

Nginx作为目前最流行的Web服务器和反向代理,官方数据显示单机可以轻松处理10万+的并发连接。但实际生产环境中,很多同学拿到默认配置就直接上了,结果发现连1万并发都扛不住。问题不在Nginx本身,而在于配置。

1.2 技术特点

Nginx采用事件驱动的异步非阻塞架构,这跟传统的Apache每个连接一个进程/线程的模式完全不同。打个比方:Apache像是银行柜台,每个客户都需要一个柜员全程服务;Nginx则像是叫号系统,一个柜员可以同时处理多个客户的不同阶段任务。

核心优势:

  • 内存占用低:处理10000个非活跃HTTP keep-alive连接仅需2.5MB内存
  • 事件驱动:基于epoll/kqueue,不会因为连接数增加而线性增长CPU消耗
  • 模块化设计:只加载需要的模块,减少资源浪费
  • 热部署:配置修改无需重启,平滑reload

1.3 适用场景

  • 高并发静态资源服务(图片、CSS、JS、视频)
  • 反向代理和负载均衡
  • API网关
  • SSL/TLS终结点
  • 缓存服务器
  • WebSocket代理

1.4 环境要求

组件 版本 说明
操作系统 Rocky Linux 9.4 / Ubuntu 24.04 LTS 内核版本建议5.15+
Nginx 1.26.2 / 1.27.0 mainline版本功能更新,stable版本更稳定
CPU 8核+ Nginx worker数量与CPU核心数相关
内存 16GB+ 主要用于连接缓冲和缓存
网络 万兆网卡 千兆网卡在高并发下会成为瓶颈
磁盘 NVMe SSD 日志写入和缓存需要高IOPS

二、详细步骤

2.1 准备工作

2.1.1 系统内核参数调优

在动Nginx配置之前,得先把操作系统底子打好。很多人忽略了这一步,结果Nginx配得再好也白搭。

# /etc/sysctl.conf 追加以下内容

# 文件描述符限制
fs.file-max = 2097152
fs.nr_open = 2097152

# TCP连接相关
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# TIME_WAIT优化(这个参数救过我无数次)
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_max_tw_buckets = 262144

# TCP keepalive
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3

# 网络缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# 本地端口范围
net.ipv4.ip_local_port_range = 1024 65535

应用配置:

sysctl -p

2.1.2 文件描述符限制

这是个老生常谈的问题了,但每次接手新项目还是会遇到。Nginx报"Too many open files"错误,十有八九就是这个没配好。

# /etc/security/limits.conf
* soft nofile 1048576
* hard nofile 1048576
nginx soft nofile 1048576
nginx hard nofile 1048576

# /etc/systemd/system/nginx.service.d/override.conf
[Service]
LimitNOFILE=1048576

2.2 核心配置

法则1:worker进程数量配置

# 自动检测CPU核心数,省心省力
worker_processes auto;

# 或者手动指定,建议等于CPU核心数
# worker_processes 8;

# CPU亲和性绑定,减少CPU缓存失效
worker_cpu_affinity auto;

踩坑记录:早期我喜欢把worker_processes设成CPU核心数的2倍,觉得这样能处理更多请求。结果发现这是典型的过度优化,多出来的worker进程反而增加了上下文切换开销,QPS不升反降。

法则2:worker连接数配置

events {
    # 每个worker的最大连接数
    # 理论最大并发 = worker_processes * worker_connections
    worker_connections 65535;

    # 使用epoll事件模型(Linux 2.6+必选)
    use epoll;

    # 允许一个worker进程同时接受多个新连接
    multi_accept on;

    # 互斥锁,高并发场景建议关闭
    accept_mutex off;
}

法则3:文件描述符缓存

# main context
worker_rlimit_nofile 1048576;

法则4:sendfile零拷贝

http {
    # 开启sendfile,避免用户态和内核态之间的数据拷贝
    sendfile on;

    # 配合sendfile使用,减少网络报文段数量
    tcp_nopush on;

    # 禁用Nagle算法,减少延迟
    tcp_nodelay on;
}

原理解释:传统文件发送需要经历"磁盘->内核缓冲区->用户缓冲区->socket缓冲区"四次拷贝。sendfile直接在内核态完成"磁盘->socket缓冲区"的数据传输,理论上可以提升30%-40%的吞吐量。

法则5:超时配置

http {
    # 客户端请求头超时
    client_header_timeout 15s;

    # 客户端请求体超时
    client_body_timeout 15s;

    # 响应超时
    send_timeout 15s;

    # keepalive超时
    keepalive_timeout 65s;

    # keepalive请求数量限制
    keepalive_requests 10000;
}

踩坑记录:曾经有个项目,上传大文件总是失败。排查半天发现是client_body_timeout设成了10秒,但大文件上传需要更长时间。生产环境这个值建议根据实际业务调整,不要一刀切。

法则6:缓冲区配置

http {
    # 客户端请求体缓冲区
    client_body_buffer_size 128k;
    client_max_body_size 100m;

    # 请求头缓冲区
    client_header_buffer_size 4k;
    large_client_header_buffers 4 32k;

    # 代理缓冲区
    proxy_buffer_size 64k;
    proxy_buffers 8 128k;
    proxy_busy_buffers_size 256k;
}

法则7:Gzip压缩

http {
    gzip on;
    gzip_vary on;
    gzip_proxied any;

    # 压缩级别1-9,建议4-6,太高CPU消耗大
    gzip_comp_level 5;

    # 最小压缩长度,太小的文件压缩反而浪费CPU
    gzip_min_length 1024;

    # 压缩类型
    gzip_types
        text/plain
        text/css
        text/javascript
        application/javascript
        application/json
        application/xml
        application/xml+rss
        image/svg+xml;

    # 预压缩文件支持
    gzip_static on;
}

性能对比

压缩级别 压缩率 CPU消耗 适用场景
1 最低 CPU受限环境
4-5 中等 通用场景(推荐)
9 最高 带宽极其昂贵

法则8:静态文件缓存

http {
    # 打开文件缓存
    open_file_cache max=100000 inactive=60s;
    open_file_cache_valid 60s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
}

server {
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }
}

法则9:日志优化

http {
    # 使用缓冲写入,减少磁盘IO
    access_log /var/log/nginx/access.log main buffer=64k flush=5s;

    # 或者对于高并发场景,考虑关闭access log
    # access_log off;

    # 错误日志级别
    error_log /var/log/nginx/error.log warn;
}

血泪教训:生产环境日志不要开debug级别!我曾经为了排查问题临时开了debug,结果磁盘一会儿就满了,服务直接挂掉。

法则10:SSL/TLS优化

http {
    # SSL会话缓存
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets on;

    # SSL协议版本
    ssl_protocols TLSv1.2 TLSv1.3;

    # 优先使用服务器端加密套件
    ssl_prefer_server_ciphers off;

    # TLS 1.3加密套件
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
}

法则11:HTTP/2配置

server {
    listen 443 ssl;
    http2 on;

    # HTTP/2推送(Nginx 1.25.1+)
    # 注意:主流浏览器已逐步废弃Server Push
}

法则12:连接复用优化

upstream backend {
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;

    # 与后端保持的连接数
    keepalive 300;

    # 单个连接最大请求数
    keepalive_requests 10000;

    # 连接超时
    keepalive_timeout 60s;
}

server {
    location /api/ {
        proxy_pass http://backend;

        # 必须使用HTTP/1.1才能使用keepalive
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

这条救命配置:很多人配了upstream的keepalive但不生效,99%是因为没加proxy_set_header Connection ""。默认情况下Nginx会把Connection头设成close,导致每次请求都新建连接。

法则13:负载均衡算法选择

upstream backend {
    # 最少连接数算法,推荐
    least_conn;

    # 或者IP哈希(需要会话保持时使用)
    # ip_hash;

    # 或者一致性哈希
    # hash $request_uri consistent;

    server 10.0.0.1:8080 weight=3;
    server 10.0.0.2:8080 weight=2;
    server 10.0.0.3:8080 weight=1 backup;
}

法则14:健康检查

upstream backend {
    server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
    server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;
}

开源版Nginx的健康检查比较弱,只能被动检测。如果需要主动健康检查,建议:

  • 使用Nginx Plus(商业版)
  • 使用第三方模块nginx_upstream_check_module
  • 使用OpenResty

法则15:请求限流

http {
    # 定义限流区域
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
}

server {
    location /api/ {
        # 请求速率限制
        limit_req zone=api_limit burst=200 nodelay;

        # 并发连接限制
        limit_conn conn_limit 50;

        # 限流返回码
        limit_req_status 429;
        limit_conn_status 429;
    }
}

法则16:proxy优化

location /api/ {
    proxy_pass http://backend;

    # 连接超时
    proxy_connect_timeout 5s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;

    # 失败重试
    proxy_next_upstream error timeout http_502 http_503;
    proxy_next_upstream_tries 3;
    proxy_next_upstream_timeout 10s;

    # 请求头传递
    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;
}

法则17:缓存配置

http {
    # 定义缓存路径
    proxy_cache_path /var/cache/nginx levels=1:2
        keys_zone=api_cache:100m
        max_size=10g
        inactive=60m
        use_temp_path=off;
}

server {
    location /api/public/ {
        proxy_pass http://backend;
        proxy_cache api_cache;
        proxy_cache_valid 200 10m;
        proxy_cache_valid 404 1m;
        proxy_cache_use_stale error timeout updating;
        proxy_cache_lock on;

        add_header X-Cache-Status $upstream_cache_status;
    }
}

法则18:安全加固

http {
    # 隐藏版本号
    server_tokens off;

    # 安全响应头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}

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

法则19:状态监控

server {
    listen 127.0.0.1:8080;

    location /nginx_status {
        stub_status on;
        allow 127.0.0.1;
        deny all;
    }
}

法则20:平滑重载

# 检查配置文件语法
nginx -t

# 平滑重载配置
nginx -s reload

# 或者使用systemd
systemctl reload nginx

2.3 启动和验证

# 检查配置
nginx -t

# 启动服务
systemctl start nginx
systemctl enable nginx

# 验证运行状态
systemctl status nginx
curl -I http://localhost

三、示例代码和配置

3.1 完整配置示例

这是一份经过实战检验的完整配置,适用于10万并发场景:

# /etc/nginx/nginx.conf

user nginx;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 1048576;

error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;

events {
    worker_connections 65535;
    use epoll;
    multi_accept on;
    accept_mutex off;
}

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" '
                    '$request_time $upstream_response_time';

    log_format json escape=json '{'
        '"time":"$time_iso8601",'
        '"remote_addr":"$remote_addr",'
        '"method":"$request_method",'
        '"uri":"$uri",'
        '"status":$status,'
        '"body_bytes_sent":$body_bytes_sent,'
        '"request_time":$request_time,'
        '"upstream_response_time":"$upstream_response_time"'
    '}';

    access_log /var/log/nginx/access.log main buffer=64k flush=5s;

    # 基础优化
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    server_tokens off;

    # 超时配置
    keepalive_timeout 65;
    keepalive_requests 10000;
    client_header_timeout 15;
    client_body_timeout 15;
    send_timeout 15;

    # 缓冲区
    client_body_buffer_size 128k;
    client_max_body_size 100m;
    client_header_buffer_size 4k;
    large_client_header_buffers 4 32k;

    # Gzip压缩
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 5;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/javascript
               application/javascript application/json
               application/xml image/svg+xml;

    # 文件缓存
    open_file_cache max=100000 inactive=60s;
    open_file_cache_valid 60s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;

    # SSL优化
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets on;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;

    # 限流配置
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    # 代理缓存
    proxy_cache_path /var/cache/nginx levels=1:2
        keys_zone=api_cache:100m
        max_size=10g
        inactive=60m
        use_temp_path=off;

    # 上游服务器
    upstream backend {
        least_conn;
        keepalive 300;
        keepalive_requests 10000;
        keepalive_timeout 60s;

        server 10.0.0.1:8080 weight=3 max_fails=3 fail_timeout=30s;
        server 10.0.0.2:8080 weight=3 max_fails=3 fail_timeout=30s;
        server 10.0.0.3:8080 weight=2 max_fails=3 fail_timeout=30s;
    }

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

3.2 实际应用案例

案例1:电商平台静态资源服务器

背景:日均UV 500万,静态资源请求峰值QPS 5万

server {
    listen 80;
    listen 443 ssl;
    http2 on;
    server_name static.example.com;

    ssl_certificate /etc/nginx/ssl/static.example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/static.example.com.key;

    root /data/static;

    # 图片资源
    location ~* \.(jpg|jpeg|png|gif|webp|ico)$ {
        expires 365d;
        add_header Cache-Control "public, immutable";
        add_header Vary Accept;
        access_log off;

        # WebP自动转换
        set $webp "";
        if ($http_accept ~* "webp") {
            set $webp ".webp";
        }
        try_files $uri$webp $uri =404;
    }

    # CSS/JS资源
    location ~* \.(css|js)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # 字体资源
    location ~* \.(woff|woff2|ttf|eot)$ {
        expires 365d;
        add_header Cache-Control "public, immutable";
        add_header Access-Control-Allow-Origin *;
        access_log off;
    }
}

效果:优化后平均响应时间从15ms降到3ms,带宽使用减少40%(Gzip功劳)。

案例2:API网关配置

背景:微服务架构,需要统一入口,QPS峰值3万

upstream user_service {
    least_conn;
    keepalive 100;
    server 10.0.1.1:8080 max_fails=2 fail_timeout=10s;
    server 10.0.1.2:8080 max_fails=2 fail_timeout=10s;
}

upstream order_service {
    least_conn;
    keepalive 100;
    server 10.0.2.1:8080 max_fails=2 fail_timeout=10s;
    server 10.0.2.2:8080 max_fails=2 fail_timeout=10s;
}

server {
    listen 443 ssl;
    http2 on;
    server_name api.example.com;

    ssl_certificate /etc/nginx/ssl/api.example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/api.example.com.key;

    # 公共配置
    proxy_http_version 1.1;
    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_set_header Connection "";

    # 用户服务
    location /api/v1/users {
        limit_req zone=api_limit burst=50 nodelay;
        proxy_pass http://user_service;
        proxy_connect_timeout 3s;
        proxy_read_timeout 30s;
    }

    # 订单服务
    location /api/v1/orders {
        limit_req zone=api_limit burst=100 nodelay;
        proxy_pass http://order_service;
        proxy_connect_timeout 3s;
        proxy_read_timeout 60s;
    }

    # 健康检查
    location /health {
        access_log off;
        return 200 'OK';
        add_header Content-Type text/plain;
    }
}

四、最佳实践和注意事项

4.1 最佳实践

  1. 配置分离管理
    • 主配置只放全局参数
    • 每个虚拟主机独立配置文件
    • 使用include指令加载
  2. 灰度发布配置
split_clients $remote_addr $variant {
    10% backend_new;
    *   backend_old;
}

location /api/ {
    proxy_pass http://$variant;
}
  1. 配置版本控制
    • 所有配置纳入Git管理
    • 变更前必须review
    • 保留回滚版本
  2. 监控告警
    • 集成Prometheus + Grafana
    • 设置QPS、响应时间、错误率告警
    • 定期review性能数据

4.2 注意事项

常见错误 原因分析 解决方案
worker_connections不生效 系统文件描述符限制 检查ulimit -n和worker_rlimit_nofile
keepalive不生效 未设置proxy_http_version和Connection头 添加proxy_http_version 1.1和proxy_set_header Connection ""
Gzip不生效 Content-Type未在gzip_types列表中 添加对应的MIME类型
SSL握手慢 未启用session缓存 配置ssl_session_cache
499错误多 客户端提前断开 检查后端响应时间,调整超时设置
502/504错误 后端超时或不可用 检查upstream健康状态,调整超时参数

五、故障排查和监控

5.1 故障排查

5.1.1 常用排查命令

# 检查Nginx进程状态
ps aux | grep nginx

# 查看监听端口
ss -tlnp | grep nginx

# 实时查看访问日志
tail -f /var/log/nginx/access.log

# 实时查看错误日志
tail -f /var/log/nginx/error.log

# 查看连接状态统计
ss -s

# 查看TIME_WAIT连接数
ss -ant | grep TIME-WAIT | wc -l

# 测试配置文件
nginx -t

# 查看编译参数
nginx -V

5.1.2 性能分析

# 使用wrk进行压力测试
wrk -t12 -c400 -d30s http://localhost/api/test

# 使用ab进行压力测试
ab -n 10000 -c 100 http://localhost/api/test

# 查看nginx_status
curl http://127.0.0.1:8080/nginx_status

# 输出示例:
# Active connections: 2341
# server accepts handled requests
#  12847123 12847123 45123847
# Reading: 12 Writing: 89 Waiting: 2240

5.2 性能监控

5.2.1 Prometheus集成

# 需要安装nginx-prometheus-exporter
# 配置stub_status后,使用exporter采集数据

server {
    listen 127.0.0.1:8080;
    location /nginx_status {
        stub_status on;
        allow 127.0.0.1;
        deny all;
    }
}

Prometheus配置:

scrape_configs:
  - job_name: 'nginx'
    static_configs:
      - targets: ['localhost:9113']

5.2.2 关键指标监控

指标 告警阈值 说明
nginx_http_requests_total - 请求总数,用于计算QPS
nginx_connections_active > 80% worker_connections 活跃连接数
nginx_connections_waiting - 等待连接数
5xx错误率 > 1% 服务端错误
平均响应时间 > 500ms 响应时间
upstream响应时间 > 1s 后端响应时间

5.3 备份与恢复

# 配置备份脚本
#!/bin/bash
BACKUP_DIR="/data/backup/nginx"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p ${BACKUP_DIR}
tar -czf ${BACKUP_DIR}/nginx_${DATE}.tar.gz /etc/nginx/

# 保留最近30天备份
find ${BACKUP_DIR} -name "*.tar.gz" -mtime +30 -delete

# 恢复命令
tar -xzf ${BACKUP_DIR}/nginx_20250107_120000.tar.gz -C /
nginx -t && systemctl reload nginx

六、总结

6.1 技术要点回顾

这20条黄金法则覆盖了Nginx性能调优的方方面面:

  • 系统层面:内核参数、文件描述符、CPU亲和性
  • Nginx核心:worker进程、连接数、事件模型
  • 传输优化:sendfile、TCP优化、keepalive
  • 内容优化:Gzip压缩、静态缓存、代理缓存
  • 安全防护:限流、超时、安全头
  • 监控运维:状态监控、日志分析、平滑重载

实施这些优化后,我见证过的性能提升:

  • QPS从1万提升到10万+(10倍)
  • 平均响应时间从200ms降到20ms(10倍)
  • 服务器资源利用率从80%降到30%(释放了更多资源)

6.2 进阶学习方向

  1. OpenResty:整合Lua脚本,实现复杂业务逻辑
  2. Nginx Plus:商业版特性,如主动健康检查、动态配置
  3. Kubernetes Ingress:云原生场景下的Nginx应用
  4. 性能极限突破:DPDK、io_uring等新技术

6.3 参考资料

附录

A. 命令速查表

命令 说明
nginx -t 测试配置文件语法
nginx -s reload 平滑重载配置
nginx -s stop 快速停止
nginx -s quit 优雅停止
nginx -V 查看编译参数
nginx -T 输出完整配置

B. 配置参数详解

参数 默认值 推荐值 说明
worker_processes 1 auto worker进程数
worker_connections 512 65535 单worker最大连接数
keepalive_timeout 75s 65s 客户端keepalive超时
keepalive_requests 100 10000 单连接最大请求数
client_max_body_size 1m 100m 请求体最大值
gzip_comp_level 1 5 Gzip压缩级别

C. 术语表

术语 解释
QPS Queries Per Second,每秒查询数
TPS Transactions Per Second,每秒事务数
Keepalive 持久连接,复用TCP连接
Upstream 上游服务器,即后端服务
Reverse Proxy 反向代理
Load Balancing 负载均衡
epoll Linux高效的I/O事件通知机制
Zero Copy 零拷贝技术,减少数据拷贝次数

转载自:https://mp.weixin.qq.com/s/F8PigJFi_cHSOG5OCJ0_Fg

更换Git子模块的仓库地址

更换子模块地址

  1. 修改 .gitmodules
    [submodule "libs/foo"]
     path = libs/foo
     url  = https://github.com/old-org/foo.git

    改成:

    [submodule "libs/foo"]
     path = libs/foo
     url  = https://github.com/new-org/foo.git
  2. 同步配置
    git submodule sync
  3. 更新子模块
    git submodule update --init --recursive
  4. 更新仓库
    git add .gitmodules
    git commit -m "chore: update submodule foo url"
    git push

更换主仓库地址

  1. 查看当前远端
    git remote -v

    你会看到类似:

    origin  https://github.com/old-org/project.git (fetch)
    origin  https://github.com/old-org/project.git (push)
  2. 修改 origin 地址
    git remote set-url origin https://github.com/new-org/project.git

    验证

    git remote -v
  3. 推送到新组织(第一次建议加 -u)
    git push -u origin main
    # 或
    git push -u origin master

OpenVPN 管理器:面向企业 VPN 管理的完整开源解决方案

管理整个组织内的 VPN 用户不应该再像 2005 年那样了。不再需要使用包含凭据的电子表格、手动配置文件,也不再需要费心去了解“现在谁在线?”。

OpenVPN Manager——一个开源的 Web 应用程序,它为您的 VPN 基础架构带来现代化的用户管理;同时发布的还有OpenVPN Client——一个配套工具,它可以将所有内容无缝集成。

问题

如果你曾经为团队管理过 OpenVPN 服务器,你就会了解这些痛点:

  • 用户管理一片混乱——添加用户意味着生成证书、编辑配置,还要祈祷别搞砸了什么。
  • 完全看不到任何信息——谁在线?带宽使用情况如何?连接历史记录?祝你好运,希望能找到答案。
  • 访问控制难题——工程部门和人力资源部门需要不同的网络访问权限,但 OpenVPN 并没有简化这一过程。
  • 审计要求——当安全部门询问“谁在何时访问了什么?”时,您可能需要花费数小时翻阅日志。
  • 承包商访问权限——本应过期但从未过期的临时用户。

解决方案:两个项目,一个完整系统

OpenVPN 管理器(Web 应用程序)

整个系统的核心。一个基于网页的管理面板,您可以在这里管理所有事项:

基于角色的访问控制的用户管理

三个角色确保一切井然有序:

  • 用户——可以查看和编辑自己的个人资料
  • 管理员——可以创建和管理团队中的用户
  • 管理员——拥有所有权限

非常适合团队负责人需要管理团队的 VPN 访问权限,而又不想麻烦 IT 部门的组织。


基于组的网络访问

定义用户组(例如工程组、人力资源组、财务组),并为每个用户分配网络段。用户继承其所属用户的访问权限。简单、可扩展且可审计。


VPN IP 自动分配

只需配置一次 VPN 网络范围,系统就会自动为新用户分配下一个可用的 IP 地址。从此告别 IP 地址冲突和手动追踪。

会话跟踪与审核

最后,了解您的 VPN 信息:

  • 实时连接状态
  • 用户带宽使用情况
  • 完整的连接历史记录
  • 所有变更的完整审计跟踪


限时访问

需要授予承包商两周的访问权限?设置日期valid_from即可valid_to。访问权限会自动过期。再也不用担心忘记登录了。

OpenVPN客户端(集成脚本)

将你的 OpenVPN 服务器连接到管理器的 Go 二进制文件:

┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ 
│ OpenVPN 服务器 │─────────────▶│ OpenVPN 客户端 │────▶│ OpenVPN 管理器
│ │ │ │ (Go 二进制文件)                           │ │ (Web 应用) │ 
└─────────────────┘ └───────────────────┘ └───────────────────┘ 
                               │ 
                               ▼ 
                        ┌───────────────────┐ 
                        │ nftables/iptables 
                        │ │ (防火墙) │ 
                        └─────────────────┘

四个二进制文件处理所有事情:

BinaryPurpose 功能openvpn-login包括:根据 API 验证用户凭据openvpn-connect;分配 IP 地址;根据组成员身份推送路由openvpn-disconnect;记录会话结束和流量统计信息;openvpn-firewall为每个用户生成 nftables/iptables 规则。

完整安装指南

步骤 1:安装 OpenVPN 管理器

选项 A:DEB 软件包(Debian/Ubuntu)

VERSION="1.0.1" 
wget https://github.com/tldr-it-stepankutaj/openvpn-mng/releases/download/v${VERSION}/openvpn-mng_${VERSION}_linux_amd64.deb 
sudo dpkg -i openvpn-mng_${VERSION}_linux_amd64.deb

选项 B:RPM 软件包(RHEL/AlmaLinux/Rocky)

VERSION="1.0.1" 
wget https://github.com/tldr-it-stepankutaj/openvpn-mng/releases/download/v${VERSION}/openvpn-mng_${VERSION}_linux_amd64.rpm 
sudo dnf install ./openvpn-mng_${VERSION}_linux_amd64.rpm

选项 C:Docker

docker pull tldrit/openvpn-mng:latest

步骤 2:配置数据库

# PostgreSQL 
sudo -u postgres psql 
CREATE USER openvpn WITH PASSWORD 'your-secure-password'; 
CREATE DATABASE openvpn_mng OWNER openvpn; 
\q

步骤 3:配置 OpenVPN 管理器

# 生成密钥
JWT_SECRET=$(openssl rand -hex 32) 
VPN_TOKEN=$(openssl rand -hex 32)
echo "JWT_SECRET: $JWT_SECRET" 
echo "VPN_TOKEN: $VPN_TOKEN"
# 编辑配置文件
sudo nano /etc/openvpn-mng/config.yaml

关键设置:

database:
  type: "postgres"
  host: "localhost"
  password: "your-db-password"
  database: "openvpn_mng"
auth:
  jwt_secret: "your-generated-jwt-secret"
api:
  vpn_token: "your-generated-vpn-token"
vpn:
  network: "10.90.90.0/24"
  server_ip: "10.90.90.1"

步骤 4:启动 OpenVPN 管理器

sudo systemctl enable --now openvpn-mng.service
# 验证
curl http://localhost:8080/

默认登录名:admin/ admin123— 请立即更改!

步骤 5:安装 OpenVPN 客户端

选项 A:DEB 软件包(Debian/Ubuntu)

VERSION="1.0.0" 
wget https://github.com/tldr-it-stepankutaj/openvpn-client/releases/download/v${VERSION}/openvpn-client_${VERSION}_linux_amd64.deb 
sudo dpkg -i openvpn-client_${VERSION}_linux_amd64.deb

选项 B:RPM 软件包(RHEL/AlmaLinux/Rocky)

VERSION="1.0.0" 
wget https://github.com/tldr-it-stepankutaj/openvpn-client/releases/download/v${VERSION}/openvpn-client_${VERSION}_linux_amd64.rpm 
sudo dnf install ./openvpn-client_${VERSION}_linux_amd64.rpm

选项 C:从源代码构建

git clone https://github.com/tldr-it-stepankutaj/openvpn-client.git 
cd openvpn-client 
make build-linux 
sudo make install

步骤 6:配置 OpenVPN 客户端

sudo mkdir -p /etc/openvpn/client 
sudo nano /etc/openvpn/client/config.yaml
api:
  base_url: "http://127.0.0.1:8080"
  token: "your-vpn-token-from-step-3"
  timeout: 10s
openvpn:
  session_dir: "/var/run/openvpn"
firewall:
  type: "nftables"
  nftables:
    rules_file: "/etc/nftables.d/vpn-users.nft"
    reload_command: "/usr/sbin/nft -f /etc/sysconfig/nftables.conf"

步骤 7:配置 OpenVPN 服务器

添加到您的 OpenVPN 服务器配置中:

# VPN network (must match OpenVPN Manager config)
server 10.90.90.0 255.255.255.0
topology subnet
# Authentication via OpenVPN Manager
username-as-common-name
auth-user-pass-verify /usr/bin/openvpn-login via-file
client-connect /usr/bin/openvpn-connect
client-disconnect /usr/bin/openvpn-disconnect
script-security 2

步骤 8:设置防火墙规则定时任务

# 创建初始规则
sudo mkdir -p /etc/nftables.d 
sudo touch /etc/nftables.d/vpn-users.nft 
sudo /usr/bin/openvpn-firewall
# 添加 cron 任务
echo "*/5 * * * * root /usr/bin/openvpn-firewall >> /var/log/openvpn-firewall.log 2>&1" | sudo tee /etc/cron.d/openvpn-firewall

步骤 9:重启 OpenVPN

sudo systemctl restart openvpn@server

这一切是如何协同运作的

  1. 用户使用用户名和密码连接
  2. openvpn-login使用 Manager API 验证凭据
  3. openvpn-connect获取用户的组和网络,然后推送路由
  4. 防火墙规则根据用户的组成员身份限制流量
  5. 会话在管理器数据库中进行跟踪。
  6. 管理员可在网页界面查看实时连接。
  7. openvpn-disconnect 会在用户断开连接时记录流量统计信息。

技术栈

OpenVPN 管理器:

  • Go + Gin 框架
  • GORM(PostgreSQL/MySQL)
  • JWT 身份验证
  • Bootstrap 5 Web UI

OpenVPN客户端:

  • Go
  • nftables/iptables 支持
  • 结构化日志记录(slog)

两者都编译成单个二进制文件,可以部署到任何地方。

接下来是什么?

计划功能:

  • LDAP/Active Directory 集成
  • 双因素身份验证
  • WireGuard 支持
  • 普罗米修斯指标
  • Terraform 提供程序

开始使用

OpenVPN 管理器:

OpenVPN客户端:

这两个项目均采用 Apache 2.0 许可协议。欢迎贡献代码!

如果您厌倦了传统的 VPN 用户管理方式,不妨试试这个方法。如果您觉得它有用,请在 GitHub 上点个星标,非常感谢!

原文:https://medium.com/@stepan_95301/openvpn-manager-a-complete-open-source-solution-for-enterprise-vpn-management-fe214b8f4627