一、准备工作(在linux环境中)

1、下载nginx

本文使用的是nginx-1.28.0.tar.gz;如果需要,还需要下载openssl-3.5.2.tar.gz、pcre-8.45.tar.gz和zlib-1.3.1.tar.gz模块。版本请自行修改

2、准备好Dockerfile

PS: 为了方便最好Dockerfile、nginx-1.28.0.tar.gz、openssl-3.5.2.tar.gz、pcre-8.45.tar.gz和zlib-1.3.1.tar.gz 这五个文件在同一级目录中

FROM alpine as base

# 替换成你对应的版本就好
ARG NGINX_VERSION=1.28.0
ARG OPENSSL_VERSION=3.5.2
ARG ZLIB_VERSION=1.3.1
ARG PCRE_VERSION=8.45

ADD nginx-${NGINX_VERSION}.tar.gz /
ADD openssl-${OPENSSL_VERSION}.tar.gz /
ADD zlib-${ZLIB_VERSION}.tar.gz /
ADD pcre-${PCRE_VERSION}.tar.gz /

RUN sed -i 's@dl-cdn.alpinelinux.org@mirrors.aliyun.com@' /etc/apk/repositories && \
apk update && \
apk add --no-cache --virtual .build-deps gcc g++ make file perl linux-headers && \
cd /nginx-${NGINX_VERSION} && \
./configure --prefix=/app/nginx \
--with-cc-opt='-static -static-libgcc' \
--with-ld-opt='-static' \
--sbin-path=/sbin/nginx \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-compat \
--with-threads \
--with-file-aio \
--with-openssl=/openssl-${OPENSSL_VERSION} \
--with-zlib=/zlib-${ZLIB_VERSION} \
--with-pcre=/pcre-${PCRE_VERSION} \
--with-pcre \
--with-pcre-jit \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_slice_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-http_auth_request_module \
--with-http_addition_module \
--with-http_sub_module \
--with-stream && \
make && make install

FROM alpine

RUN addgroup -S nginx && adduser -S nginx -G nginx && \
mkdir -p /var/log/nginx /var/cache/nginx /var/run /usr/share/nginx/html && \
chown -R nginx:nginx /var/log/nginx /var/cache/nginx /var/run && \
chmod -R 755 /var/log/nginx

# 复制Nginx文件
COPY --from=base /app/nginx /app/nginx
COPY --from=base /sbin/nginx /sbin/nginx
COPY --from=base /etc/nginx /etc/nginx

# 暴露端口
EXPOSE 80

# 设置启动命令
ENTRYPOINT ["nginx", "-g", "daemon off;"]

构建镜像

docker build -t myapp .

3、在自己的项目中使用CICD查看

4、使用这个镜像和前端文件一起构建成docker应用

4.1、准备好dist.zip(前端打包好的文件)、nginx.conf以及Dockerfile

PS: 为了方便最好Dockerfile、dist.zip、nginx.conf 这三个文件在同一级目录中

# 第一阶段:解压文件
FROM alpine:latest as extractor

# 使用国内镜像源
RUN sed -i 's@dl-cdn.alpinelinux.org@mirrors.aliyun.com@' /etc/apk/repositories

COPY dist.zip /tmp/dist.zip

RUN apk add --no-cache unzip && \
unzip /tmp/dist.zip -d /app && \
rm -f /tmp/dist.zip

# 第二阶段:构建最终镜像
FROM moshangjunmowen/nginx:1.28.0

COPY --from=extractor /app /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

# 设置权限
RUN chown -R nginx:nginx /usr/share/nginx/html && \
chmod -R 755 /usr/share/nginx/html

EXPOSE 80

4.2、这里提供一份nginx.conf案例,仅供参考

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

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

# 性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
reset_timedout_connection on;

# 缓冲区设置
client_body_buffer_size 128k;
client_max_body_size 10m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
output_buffers 1 32k;
postpone_output 1460;

# 超时设置
client_body_timeout 12;
client_header_timeout 12;
send_timeout 10;

# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$gzip_ratio" $request_time $upstream_response_time';

log_format json_analytics escape=json '{'
'"msec": "$msec", '
'"connection": "$connection", '
'"connection_requests": "$connection_requests", '
'"pid": "$pid", '
'"request_id": "$request_id", '
'"request_length": "$request_length", '
'"remote_addr": "$remote_addr", '
'"remote_user": "$remote_user", '
'"remote_port": "$remote_port", '
'"time_local": "$time_local", '
'"time_iso8601": "$time_iso8601", '
'"request": "$request", '
'"request_uri": "$request_uri", '
'"args": "$args", '
'"status": "$status", '
'"body_bytes_sent": "$body_bytes_sent", '
'"bytes_sent": "$bytes_sent", '
'"http_referer": "$http_referer", '
'"http_user_agent": "$http_user_agent", '
'"http_x_forwarded_for": "$http_x_forwarded_for", '
'"http_host": "$http_host", '
'"server_name": "$server_name", '
'"request_time": "$request_time", '
'"upstream": "$upstream_addr", '
'"upstream_connect_time": "$upstream_connect_time", '
'"upstream_header_time": "$upstream_header_time", '
'"upstream_response_time": "$upstream_response_time", '
'"upstream_response_length": "$upstream_response_length", '
'"upstream_cache_status": "$upstream_cache_status", '
'"ssl_protocol": "$ssl_protocol", '
'"ssl_cipher": "$ssl_cipher", '
'"scheme": "$scheme", '
'"request_method": "$request_method", '
'"server_protocol": "$server_protocol", '
'"pipe": "$pipe", '
'"gzip_ratio": "$gzip_ratio", '
'"http_cf_ray": "$http_cf_ray"'
'}';

# 日志输出到标准输出
access_log /dev/stdout json_analytics;
error_log /dev/stderr warn;

# 限制连接
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;

# 限制请求速率
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;

# Gzip 设置
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/xml+rss
application/json
application/atom+xml
application/rss+xml
image/svg+xml;

# 启用预压缩文件
gzip_static on;

# 响应头安全设置
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;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Permissions-Policy "geolocation=(), midi=(), sync-xhr=(), microphone=(), camera=(), magnetometer=(), gyroscope=(), fullscreen=(self), payment=()" always;

# 上游服务器配置(示例)
upstream backend {
server 127.0.0.1:8080;
keepalive 32;
}

server {
listen 80;
# 如果需要HTTPS,取消注释以下行
# listen 443 ssl http2;
server_name localhost;

# SSL配置示例
# ssl_certificate /etc/ssl/certs/nginx.crt;
# ssl_certificate_key /etc/ssl/private/nginx.key;
# ssl_protocols TLSv1.2 TLSv1.3;
# ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
# ssl_prefer_server_ciphers off;
# ssl_session_cache shared:SSL:10m;
# ssl_session_timeout 10m;

root /usr/share/nginx/html;
index index.html index.htm;

# 限制连接数和请求率
limit_conn perip 10;
limit_conn perserver 100;
limit_req zone=one burst=20 nodelay;

# 安全设置 - 隐藏nginx版本
server_tokens off;

# 启用stub_status监控
location /nginx_status {
stub_status;
access_log off;
allow 127.0.0.1;
deny all;
}

# 静态资源缓存优化
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1d;
add_header Cache-Control "public, immutable";
add_header Access-Control-Allow-Origin "*";
# 启用分片处理大文件
slice 1m;
try_files $uri $uri/ =404;
}

# HTML文件 - 不缓存
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";

# 使用sub模块替换内容示例
# sub_filter '</body>' '<div style="position:fixed;bottom:0;width:100%;text-align:center;background:#f5f5f5;padding:10px;">Powered by Nginx</div></body>';
# sub_filter_once on;
}

# API代理示例
location /api/ {
# 认证请求示例
# auth_request /auth;

proxy_pass http://backend;
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;

# 真实IP设置
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
}

# 认证端点示例
location = /auth {
internal;
proxy_pass http://backend/auth/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}

# 使用addition模块添加页脚示例
location /with-footer {
# 在响应后添加内容
add_after_body /footer.html;
}

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

# 使用addition模块在响应前添加内容
add_before_body /header.txt;
}

# 处理前端路由(SPA)
location / {
try_files $uri $uri/ /index.html;

# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
}

# 错误页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;

location = /50x.html {
root /usr/share/nginx/html;
}

location = /404.html {
root /usr/share/nginx/html;
internal;
}

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

# 禁止访问敏感文件
location ~* (\.env|\.git|\.svn|composer\.json|package\.json) {
deny all;
access_log off;
log_not_found off;
}
}
}

# Stream模块配置(TCP/UDP代理)
# stream {
# 上游服务器定义
# upstream backend_tcp {
# server backend1.example.com:12345;
# server backend2.example.com:12345;
# }

# TCP代理示例
# server {
# listen 12345;
# proxy_pass backend_tcp;
# proxy_timeout 3s;
# proxy_connect_timeout 1s;
# }

# UDP代理示例
# server {
# listen 53 udp;
# proxy_pass 8.8.8.8:53;
# proxy_responses 1;
# error_log /var/log/nginx/dns_error.log;
# }
# }

4.3、执行命令

PS:先cd到存放对应文件的文件夹内

docker run -d -p 8085:80 -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf --name frontend-app my-frontend-app