Hugo博客公告弹窗

Nginx ACME 自动化管理脚本,证书自动续签

前言

系统推荐:debian12

服务器要开放80端口

nginx版本1.25以上

一键脚本,不保证100%运行无错,推荐手动

curl -sS -O https://raw.githubusercontent.com/woniu336/open_shell/main/nginx-acme-manager.sh && chmod +x nginx-acme-manager.sh && ./nginx-acme-manager.sh

以下为手动操作

安装依赖

sudo apt update
sudo apt install -y build-essential libpcre3-dev zlib1g-dev libssl-dev pkg-config libclang-dev git wget curl

安装 Rust 工具链:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

创建目录结构

mkdir -pv /app/nginx/{logs,conf,cache,acme} /app/nginx-build
cd /app/nginx-build

获取源码

下载 ACME 模块:

git clone https://github.com/nginx/nginx-acme.git /app/nginx-build/nginx-acme

下载并解压 NGINX 源码(推荐稳定版 1.28.0):

wget https://nginx.org/download/nginx-1.28.0.tar.gz
tar -zxf nginx-1.28.0.tar.gz

编译 NGINX + ACME 模块

大概5分钟

cd /app/nginx-build/nginx-1.28.0

./configure \
    --prefix=/app/nginx \
    --error-log-path=/app/nginx/logs/error.log \
    --http-log-path=/app/nginx/logs/access.log \
    --pid-path=/app/nginx/nginx.pid \
    --lock-path=/app/nginx/nginx.lock \
    --http-client-body-temp-path=/app/nginx/cache/client_temp \
    --http-proxy-temp-path=/app/nginx/cache/proxy_temp \
    --user=nginx \
    --group=nginx \
    --with-compat \
    --with-file-aio \
    --with-threads \
    --with-http_realip_module \
    --with-http_ssl_module \
    --with-http_v2_module \
    --with-http_gzip_static_module \
    --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' \
    --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' \
    --add-dynamic-module=/app/nginx-build/nginx-acme

make && make modules && make install

添加nginx用户

useradd -r -s /sbin/nologin nginx

创建目录结构

cd /app/nginx
mkdir -p logs cache/{client_temp,proxy_cache} acme/{letsencrypt,staging} conf/conf.d
chown -R nginx:nginx /app/nginx

全局nginx配置

路径:/app/nginx/conf/nginx.conf

注意:把123456@qq.com修改成自己的邮箱

nano /app/nginx/conf/nginx.conf

清除原本内容,粘贴

user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;

error_log logs/error.log warn;
pid nginx.pid;

# ACME 模块
load_module modules/ngx_http_acme_module.so;

events {
    worker_connections 4096;
    multi_accept on;
    use epoll;
}

http {
    include 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" '
                    'rt=$request_time uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" urt="$upstream_response_time"';
    access_log logs/access.log main;

    # 基础性能
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65s 60s;
    keepalive_requests 1000;
    reset_timedout_connection on;

    # === 客户端请求体配置 ===
    client_max_body_size 100m;
    client_body_buffer_size 256k;
    client_body_timeout 30s;
	
    # === 客户端请求头配置 ===
    client_header_buffer_size 4k;
    large_client_header_buffers 4 16k;
    client_header_timeout 10s;
    
    # === 临时文件路径 ===
    client_body_temp_path cache/client_temp;
    
    # === 防止慢速攻击 ===
    client_body_in_single_buffer off;

    # Gzip
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_min_length 1024;
    gzip_buffers 16 8k;
    gzip_types
        text/plain
        text/css
        application/json
        application/javascript
        application/xml+rss
        application/rss+xml
        application/atom+xml
        application/xhtml+xml
        font/truetype
        font/opentype
        application/vnd.ms-fontobject
        image/svg+xml;
    gzip_disable "msie6";

    # DNS
    resolver 8.8.8.8 1.0.0.1 valid=300s ipv6=off;
    resolver_timeout 5s;

    # 全局代理头(所有站点都生效)
    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_hide_header X-Powered-By;
    proxy_hide_header Server;

    # 隐藏 Nginx 版本号
    server_tokens off;

    # ACME
    acme_shared_zone zone=acme_shared:2M;
    acme_issuer letsencrypt {
        uri https://acme-v02.api.letsencrypt.org/directory;
        contact mailto:123456@qq.com;
        state_path acme/letsencrypt;
        accept_terms_of_service;
    }

    # SSL
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:20m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
    ssl_buffer_size 4k;

    # 全局限流(保持)
    limit_req_zone $binary_remote_addr zone=req_limit:10m rate=200r/s;
    limit_req zone=req_limit burst=300;
    limit_req_status 429;

    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
    limit_conn conn_limit 100;
    limit_conn_status 429;

    # HTTP → HTTPS 跳转
    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name _;
        location / {
            return 301 https://$host$request_uri;
        }
    }

    include conf.d/*.conf;
}

站点配置

站点路径:/app/nginx/conf/conf.d

把6.6.6.6:80,改成你要反代的源站ip和端口

2345_com是上游服务器(源站)名称,每个站点不一样,避免冲突,

backup是备用服务器的意思,源站挂了,备用顶上,需要的话移除注释

证书目录 /app/nginx/acme/letsencrypt

示例:2345.com, www.2345.com, 根域跳转到www

nano /app/nginx/conf/conf.d/2345.com.conf

粘贴以下内容

upstream 2345_com {
    server 6.6.6.6:80;
    #server 3.2.3.8:80 backup;
    keepalive 32;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;

    server_name 2345.com www.2345.com;

    # 根域名跳转
    if ($host = 2345.com) {
        return 301 https://www.2345.com$request_uri;
    }

    access_log logs/2345.com-access.log;
    error_log logs/2345.com-error.log warn;

    acme_certificate letsencrypt;
    ssl_certificate $acme_certificate;
    ssl_certificate_key $acme_certificate_key;
    ssl_certificate_cache max=2;

    # 安全头
    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;
    add_header Strict-Transport-Security "max-age=31536000" always;

    location / {
        proxy_pass http://2345_com;
        proxy_http_version 1.1;

        # 代理超时与重试
        proxy_connect_timeout 5s;
        proxy_send_timeout 15s;
        proxy_read_timeout 15s;
        proxy_next_upstream error timeout http_502 http_503 http_504;
    }

    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /app/nginx/html;
        internal;
    }
}

查看证书:

cd /app/nginx
tree acme/ modules/

需要安装tree

apt-get update && apt-get install -y tree

单域名没有跳转配置

示例:

upstream tv_2345_com {
    server 6.6.6.6:80;
	#server 3.2.3.8:80 backup;

    keepalive 32;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;

    server_name tv.2345.com;

    access_log logs/tv.2345.com-access.log;
    error_log logs/tv.2345.com-error.log warn;

    acme_certificate letsencrypt;
    ssl_certificate $acme_certificate;
    ssl_certificate_key $acme_certificate_key;
    ssl_certificate_cache max=2;

    # 安全头
    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;
    add_header Strict-Transport-Security "max-age=31536000" always;

    location / {
        proxy_pass http://tv_2345_com;
        proxy_http_version 1.1;

        # 代理超时与重试
        proxy_connect_timeout 5s;
        proxy_send_timeout 15s;
        proxy_read_timeout 15s;
        proxy_next_upstream error timeout http_502 http_503 http_504;
    }

    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /app/nginx/html;
        internal;
    }
}

验证和重载

验证配置文件语法

cd /app/nginx/
./sbin/nginx -c conf/nginx.conf -t

提示以下信息正确

nginx: the configuration file /app/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /app/nginx/conf/nginx.conf test is successful

启动,如果已经启动会提示Address already in use

cd /app/nginx/
./sbin/nginx -c conf/nginx.conf

配置变更后重载

cd /app/nginx/
./sbin/nginx -c conf/nginx.conf -s reload

禁止IP访问

已使用更简洁的方法,以下方式仅供参考。

生成自签名证书

openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
  -keyout /app/nginx/conf/default_ssl.key \
  -out /app/nginx/conf/default_ssl.crt \
  -subj "/C=CN/ST=State/L=City/O=Org/CN=_"

修改nginx全局配置

nano /app/nginx/conf/nginx.conf

修改结尾部分

    # HTTP → HTTPS 跳转
    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name _;
        location / {
            return 301 https://$host$request_uri;
        }
    }

    # 禁止 IP 直接访问(HTTPS)
    server {
        listen 443 ssl default_server;
        listen [::]:443 ssl default_server;
        http2 on;
        server_name _;
        
        ssl_certificate /app/nginx/conf/default_ssl.crt;
        ssl_certificate_key /app/nginx/conf/default_ssl.key;
        
        return 444;
    }

    include conf.d/*.conf;
}

最后重载生效

cd /app/nginx/
./sbin/nginx -c conf/nginx.conf -s reload

验证

cd /app/nginx/
./sbin/nginx -c conf/nginx.conf -t
CC BY-NC-SA 4.0 转载请注明
最后更新于 2025-10-04 15:57
clarity统计