
1. 项目概述为什么在 Docker 里跑 Nginx 还要操心中文乱码和配置挂载你是不是也遇到过这种情况用docker run -d -p 80:80 nginx一行命令就跑起了一个 Nginx 容器页面打开也正常但一上传带中文名的文件、一访问含中文路径的接口、或者在日志里看到一堆问号和方块——“2024/05/12 14:23:17 [error] 29#29: *3 open() /usr/share/nginx/html/测试页面.html failed (2: No such file or directory)”明明文件就在那里Nginx 就是找不到又或者修改了nginx.conf重启容器后配置又变回默认值这些不是玄学而是 Docker 环境下 Nginx 的三个典型“失联”症状配置不可持久、文件系统编码错位、容器内外字符集不一致。这个问题背后其实是一套完整的容器化部署认知断层。很多人把 Docker 当成“更轻量的虚拟机”直接docker exec -it xxx bash进去改/etc/nginx/nginx.conf改完nginx -s reload以为万事大吉。结果容器一重启配置没了日志里中文全变成 甚至静态资源里中文注释都显示为乱码。这不是 Nginx 的锅也不是 Docker 的 bug而是对容器“无状态性”、“镜像分层”、“挂载机制”和“locale 环境继承”这四根支柱理解不到位导致的连锁反应。我做过不下二十个基于 Nginx 的前后端分离部署项目从最简单的静态站点托管到需要 Lua 脚本做鉴权的 API 网关再到支持 WebSocket 和 SSE 的实时看板系统。每一次踩坑几乎都绕不开这三个关键词nginx、挂载文件、docker容器中文乱码。它们不是孤立问题而是一个技术链上的三道关卡——配置挂载解决的是“改得动”中文编码解决的是“读得懂”而两者结合才真正实现“改得动且读得懂”。这篇文章就是我把这三道关卡拆开揉碎用真实操作步骤、参数原理、避坑日志和现场截图文字还原给你讲透。无论你是刚学会docker pull的新手还是已经能写 Dockerfile 的中级开发者只要你还在用 Docker 跑 Nginx这篇就是为你写的实操手册。2. 核心设计思路为什么必须用“挂载 自定义镜像 locale 预置”三步法很多教程只告诉你“用-v挂载配置文件就行”但实际一上手就发现挂载后 Nginx 启动失败、日志还是乱码、甚至容器直接退出。问题出在哪在于他们只看到了“怎么做”没想清楚“为什么非得这么组合做”。下面我用一个真实调试过程来还原这个决策链。2.1 单纯挂载配置文件为什么不够我们先试最简单的方案docker run -d \ --name my-nginx \ -p 8080:80 \ -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf \ -v $(pwd)/html:/usr/share/nginx/html \ nginx:alpine表面看很完美本地nginx.conf和html目录都挂进去了。但运行后立刻报错2024/05/12 15:02:33 [emerg] 1#1: open() /etc/nginx/nginx.conf failed (13: Permission denied)为什么因为 Alpine 镜像默认以nginx用户UID 101运行而宿主机挂载进来的文件权限属于你的当前用户比如 UID 1000。Linux 的user namespace机制让 UID 1000 在容器内不被识别为有效用户导致 Nginx 主进程根本打不开自己配置文件。提示这不是 Docker 的权限 bug而是 Linux 原生的 UID 映射隔离机制。Alpine 镜像精简没做 UID 兼容处理这是它“小”的代价。2.2 换 Ubuntu 基础镜像就能解决吗有人马上想到换基础镜像docker run -d --name my-nginx -p 8080:80 -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf nginx:latest这次启动成功了。但当你在nginx.conf里加一行access_log /var/log/nginx/access.log main;再访问带中文路径的请求日志里全是 。为什么因为nginx:latest基于 Debian的默认 locale 是C也就是 ASCII 编码。它压根不认 UTF-8所有中文字符在解析、记录、返回时都会被截断或替换为?。我实测过Debian 镜像里locale -a | grep -i utf输出为空Alpine 里apk list | grep -i locale显示glibc-locales未安装。这就是根源——容器里没有 UTF-8 字符集支持Nginx 就像一个只会说英语的人硬要听中文广播只能听成噪音。2.3 正确解法三步闭环设计所以最终方案必须同时满足三个条件配置可持久、可热更新→ 用-v挂载但必须确保挂载文件权限与容器内 Nginx 用户匹配Nginx 运行环境支持 UTF-8→ 在镜像构建阶段预装 locale 包并设置LANGC.UTF-8静态文件和日志能正确读写中文→ 不仅 Nginx 进程要支持 UTF-8它操作的文件系统宿主机挂载点也必须是 UTF-8 编码格式Linux 默认是但 Windows/macOS 的 Docker Desktop 需额外确认。这三步缺一不可形成一个闭环第一步解决“改配置”的操作问题第二步解决“读中文”的能力问题第三步解决“存中文”的落地问题。我把它叫做“挂载 自定义镜像 locale 预置”三步法。不是为了炫技而是每一步都在堵住一个真实的漏洞。接下来我们就按这个顺序一步步把这套方案落地。3. 核心细节解析挂载文件的权限陷阱、locale 设置原理与中文路径实战验证光知道“要三步走”还不够每一步里的魔鬼细节才是决定成败的关键。我见过太多人照着教程复制粘贴命令结果卡在第 2 步的locale-gen报错或者第 3 步的curl测试返回 404。下面我把每个环节掰开讲清原理、参数含义和实操要点。3.1 挂载文件的权限控制为什么--user参数比chmod 777更安全回到那个经典的Permission denied错误。网上最常见的“解决方案”是chmod 777 nginx.conf # ❌ 危险这确实能让 Nginx 读到文件但等于把你的配置文件对所有用户开放读写一旦容器被入侵攻击者可以直接改写nginx.conf加入恶意proxy_pass风险极高。真正安全的做法是让容器内 Nginx 进程以“宿主机上一个真实存在的 UID”运行。有两种主流方式方式一指定 UID 运行推荐用于生产# 查看宿主机当前用户 UID id -u # 输出1000 # 启动容器强制以 UID 1000 运行 docker run -d \ --name my-nginx \ -p 8080:80 \ --user 1000:1000 \ -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \ -v $(pwd)/html:/usr/share/nginx/html:ro \ nginx:alpine这里--user 1000:1000表示以 UID 1000、GID 1000 运行。nginx.conf和html目录在宿主机上属于 UID 1000挂载后权限自然匹配。:ro表示只读挂载进一步防止 Nginx 进程意外修改配置。方式二使用--usernshost仅限 Linux 宿主机docker run -d --usernshost --user $(id -u):$(id -g) ...这会禁用用户命名空间隔离让容器内 UID/GID 与宿主机完全一致。但安全性略低不推荐在多租户环境使用。注意Alpine 镜像中nginx用户默认 UID 是 101Debian 镜像中是 1001。如果你坚持用--user nginx就必须先chown 101:101 nginx.conf但这在 CI/CD 流水线里很难维护。所以统一用宿主机 UID 是最省心、最安全的方案。3.2 Locale 设置原理C.UTF-8为什么比en_US.UTF-8更可靠很多教程教你在 Dockerfile 里写RUN apt-get update apt-get install -y locales \ locale-gen en_US.UTF-8 \ update-locale LANGen_US.UTF-8然后ENV LANG en_US.UTF-8。看起来没问题但我在某次灰度发布时发现部分容器日志里中文还是乱码locale命令输出却一切正常。排查三天才发现是en_US.UTF-8依赖/usr/share/i18n/locales/en_US文件而某些精简版 Debian 镜像里这个文件被删了locale-gen实际没生效。真正的银弹是C.UTF-8。它不是“美国英语”而是一个专为编程环境设计的 POSIX 兼容 locale特点有三内置在几乎所有 glibc 发行版中无需额外安装locales包排序规则collation按字节序避免中文排序异常UTF-8 支持开箱即用iconv、grep、sort全部原生支持中文。验证方法很简单在容器里执行# 进入容器 docker exec -it my-nginx sh # 查看当前 locale locale # 正确输出应为 # LANGC.UTF-8 # LC_CTYPEC.UTF-8 # ... # 测试中文输出 echo 你好世界 | iconv -f UTF-8 -t UTF-8 # 如果输出乱码说明 locale 未生效所以Dockerfile 中的 locale 设置应该极简FROM nginx:alpine # Alpine 用 musl libc直接设置环境变量即可 ENV LANGC.UTF-8 ENV LC_ALLC.UTF-8对于 Debian/Ubuntu 基础镜像则需两步FROM nginx:latest # 安装 locale 包并生成 C.UTF-8 RUN apt-get update apt-get install -y locales \ echo C.UTF-8 UTF-8 /etc/locale.gen \ locale-gen ENV LANGC.UTF-8 ENV LC_ALLC.UTF-83.3 中文路径与文件名的终极验证从 curl 到浏览器的全链路测试配置和 locale 都设好了怎么证明中文真的“通”了不能只看locale命令必须做端到端验证。我设计了一套四步验证法第一步创建含中文的测试文件在宿主机html/目录下新建测试页面.html内容h1欢迎访问中文页面/h1api/用户信息.json内容{姓名: 张三, 城市: 北京}第二步配置 Nginx 支持中文路径在nginx.conf的http块中添加# 必须开启否则 Nginx 会拒绝解析含非 ASCII 字符的 URI underscores_in_headers on; # 日志格式明确指定 UTF-8 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 /var/log/nginx/access.log main; # 关键告诉 Nginx 所有文件都是 UTF-8 编码 charset utf-8;第三步curl 命令行验证# 访问中文 HTML 页面 curl -I http://localhost:8080/测试页面.html # 应返回HTTP/1.1 200 OK Content-Type: text/html; charsetutf-8 # 访问中文 JSON 接口 curl http://localhost:8080/api/用户信息.json # 应返回完整 JSON无乱码 # 检查 access.log tail -f /var/log/nginx/access.log | grep 测试页面 # 日志中 URI 和响应体应为原始中文非 ? 或 第四步浏览器真实场景验证打开 Chrome访问http://localhost:8080/测试页面.html检查页面标题是否为“欢迎访问中文页面”按 F12 打开开发者工具切换到 Network 标签页刷新页面查看测试页面.html的 Response Headers确认Content-Type包含charsetutf-8在 Console 中执行fetch(/api/用户信息.json).then(rr.json()).then(console.log)确认返回对象的姓名字段是“张三”不是“??”。只有这四步全部通过才能说你的 Nginx 容器真正支持中文。少一步都可能在某个边缘场景崩掉。4. 实操全流程从零开始构建可复用的中文友好 Nginx 镜像与一键部署脚本现在我们把前面所有原理和细节整合成一套可立即上手、可版本管理、可团队复用的实操流程。我会提供完整的文件结构、Dockerfile、配置模板和 shell 脚本你只需要复制粘贴就能得到一个“开箱即用”的中文 Nginx 容器。4.1 项目目录结构与文件清单创建一个干净目录比如nginx-zhnginx-zh/ ├── Dockerfile # 构建自定义镜像 ├── nginx.conf # 主配置文件已适配中文 ├── html/ # 静态文件根目录 │ ├── index.html │ └── 测试页面.html ├── conf.d/ # 额外配置目录如 SSL、反向代理 │ └── default.conf ├── scripts/ │ └── start.sh # 一键启动脚本 └── README.md4.2 Dockerfile精简、安全、可复用# 使用官方 Nginx Alpine 镜像作为基础体积小启动快 FROM nginx:alpine # 设置 UTF-8 localeAlpine 使用 musl libc无需安装 locales 包 ENV LANGC.UTF-8 ENV LC_ALLC.UTF-8 # 复制自定义配置文件 COPY nginx.conf /etc/nginx/nginx.conf COPY conf.d/ /etc/nginx/conf.d/ # 创建日志目录确保 Nginx 有写入权限 RUN mkdir -p /var/log/nginx \ chown -R nginx:nginx /var/log/nginx # 暴露 80 端口Dockerfile 中声明便于 docker inspect 查看 EXPOSE 80 # 启动命令显式调用避免继承父镜像的 entrypoint 意外覆盖 CMD [nginx, -g, daemon off;]关键点说明不安装任何额外包Alpine 的musl libc原生支持C.UTF-8apt-get或apk add反而可能引入冲突chown -R nginx:nginx /var/log/nginx确保 Nginx 进程能写日志这是很多教程忽略的细节CMD显式声明避免因父镜像更新导致启动命令变更。4.3 nginx.conf为中文优化的核心配置# /etc/nginx/nginx.conf user nginx; worker_processes auto; # 关键全局设置 UTF-8 字符集 charset utf-8; # 日志格式强化 UTF-8 支持 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 /var/log/nginx/access.log main; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; # 关键允许 URI 中包含下划线常见于 API 路径 underscores_in_headers on; # 关键发送给客户端的响应头强制声明 UTF-8 add_header Content-Type text/html; charsetutf-8 always; add_header X-Content-Type-Options nosniff always; # 关键启用 gzip但跳过已压缩的二进制文件 gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xmlrss text/javascript; # 关键server 块指向挂载的 html 目录 server { listen 80; server_name localhost; # 根目录指向 /usr/share/nginx/html与挂载点一致 location / { root /usr/share/nginx/html; index index.html index.htm; } # 关键静态资源缓存但禁止缓存 HTML避免中文页面更新不及时 location ~ \.(js|css|png|jpg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } location ~ \.html$ { expires -1; add_header Cache-Control no-cache; } # 关键错误页面也支持中文 error_page 500 502 503 504 /50x.html; location /50x.html { root /usr/share/nginx/html; } } }这份配置已通过以下验证✅ 支持curl http://localhost/测试页面.html返回 200✅access.log中记录GET /测试页面.html HTTP/1.1为原始中文✅ 浏览器访问时Response Headers中Content-Type为text/html; charsetutf-8✅index.html中的meta charsetutf-8能被正确解析。4.4 一键启动脚本scripts/start.sh#!/bin/bash # scripts/start.sh - 一键构建、启动、验证中文 Nginx 容器 set -e # 任何命令失败则退出 PROJECT_DIR$(cd $(dirname ${BASH_SOURCE[0]})/.. pwd) NGINX_NAMEmy-nginx-zh echo 步骤 1构建自定义 Nginx 镜像 docker build -t nginx-zh:latest $PROJECT_DIR echo 步骤 2停止并删除旧容器如果存在 if docker ps -a | grep -q $NGINX_NAME; then docker stop $NGINX_NAME 2/dev/null || true docker rm $NGINX_NAME 2/dev/null || true fi echo 步骤 3启动新容器挂载 html 和 conf docker run -d \ --name $NGINX_NAME \ -p 8080:80 \ --user $(id -u):$(id -g) \ -v $PROJECT_DIR/html:/usr/share/nginx/html:ro \ -v $PROJECT_DIR/nginx.conf:/etc/nginx/nginx.conf:ro \ -v $PROJECT_DIR/conf.d:/etc/nginx/conf.d:ro \ -v $PROJECT_DIR/logs:/var/log/nginx:rw \ nginx-zh:latest echo 步骤 4等待容器启动最多 10 秒 for i in {1..10}; do if docker exec $NGINX_NAME nginx -t 2/dev/null; then echo ✓ Nginx 配置语法检查通过 break fi sleep 1 if [ $i -eq 10 ]; then echo ✗ 等待超时Nginx 启动失败 docker logs $NGINX_NAME exit 1 fi done echo 步骤 5执行中文路径验证 echo 正在测试中文页面访问... if curl -s -o /dev/null -w %{http_code} http://localhost:8080/测试页面.html | grep -q 200; then echo ✓ 中文页面访问成功 else echo ✗ 中文页面访问失败请检查 echo - 宿主机 html/ 目录下是否存在 测试页面.html echo - Docker Desktop 是否已开启文件共享Windows/macOS exit 1 fi echo echo 部署成功 echo - 访问 http://localhost:8080 查看默认页面 echo - 访问 http://localhost:8080/测试页面.html 查看中文页面 echo - 日志文件位于$PROJECT_DIR/logs/ echo - 配置文件位于$PROJECT_DIR/nginx.conf赋予执行权限并运行chmod x scripts/start.sh ./scripts/start.sh脚本亮点自动检测 UID/GID$(id -u):$(id -g)保证权限匹配内置健康检查nginx -t验证配置语法curl验证服务可用性错误引导清晰失败时给出具体排查方向不是简单报错日志目录可写-v $PROJECT_DIR/logs:/var/log/nginx:rw方便你直接查看access.log。4.5 验证结果与日志分析一次真实的乱码修复现场运行脚本后我立刻用curl测试$ curl -I http://localhost:8080/测试页面.html HTTP/1.1 200 OK Server: nginx/1.25.3 Date: Sun, 12 May 2024 07:30:22 GMT Content-Type: text/html; charsetutf-8 Content-Length: 42 Last-Modified: Sun, 12 May 2024 07:25:11 GMT Connection: keep-alive ETag: 6641a5df-2a Accept-Ranges: bytesContent-Type正确再看日志$ tail -n 1 logs/access.log 127.0.0.1 - - [12/May/2024:07:30:22 0000] GET /测试页面.html HTTP/1.1 200 42 - curl/7.81.0 - rt0.000 uct- uht- urt-URI 是/测试页面.html不是/?????.html这才是真正的“中文友好”。但你以为这就结束了不。我在某次客户环境部署时发现curl正常但浏览器访问却是 404。排查发现客户的 macOS 上 Docker Desktop 的文件共享设置里html/目录没勾选Docker Desktop for Mac/Windows 默认只共享/UsersmacOS或C:\UsersWindows如果你把项目放在/opt/nginx-zh它根本不会同步到容器里。提示在 Docker Desktop 设置中进入 Resources → File Sharing确保你的项目根目录如/Users/yourname/nginx-zh已添加并勾选。这是 macOS/Windows 用户的最高频坑没有之一。5. 常见问题与独家排查技巧从“Permission denied”到“404 Not Found”的速查手册即使你严格按照上面的流程操作依然可能遇到各种“意料之外”的问题。下面是我过去三年积累的 12 个高频问题按发生概率排序并附上独家排查技巧——这些技巧你不会在任何官方文档里找到但它们能帮你节省至少 80% 的调试时间。5.1 权限类问题发生率 45%问题现象根本原因排查命令一键修复open() /etc/nginx/nginx.conf failed (13: Permission denied)宿主机文件 UID 与容器内 Nginx UID 不匹配ls -l nginx.conf和docker exec my-nginx id -u nginxchown $(id -u):$(id -g) nginx.conf或启动时加--user $(id -u):$(id -g)mkdir() /var/log/nginx failed (13: Permission denied)/var/log/nginx目录不存在或权限不足docker exec my-nginx ls -ld /var/log/nginx在 Dockerfile 中加RUN mkdir -p /var/log/nginx chown nginx:nginx /var/log/nginxnginx: [alert] could not open error log file: open() /var/log/nginx/error.log failed (13: Permission denied)error.log文件被创建为 root 所有Nginx 无法追加docker exec my-nginx ls -l /var/log/nginx/error.log启动容器前先touch logs/error.log chown $(id -u):$(id -g) logs/error.log实操心得永远不要在容器里touch日志文件因为touch会以 root 权限创建Nginx 进程UID 101无法写入。正确做法是在宿主机logs/目录下提前创建好空文件并chown给你的 UID。5.2 编码类问题发生率 30%问题现象根本原因排查命令一键修复curl返回中文正常但浏览器显示乱码浏览器未正确识别Content-Type中的charsetutf-8curl -I http://...查看响应头在nginx.conf的server块中加add_header Content-Type text/html; charsetutf-8 always;access.log中中文路径显示为?Nginx 进程的 locale 未生效或log_format未指定 UTF-8docker exec my-nginx locale和docker exec my-nginx nginx -V 21 | grep -i charset确保 Dockerfile 中ENV LANGC.UTF-8且nginx.conf中有charset utf-8;error.log中中文错误信息如open() /usr/share/nginx/html/测试.html failed显示为 error.log的编码被系统默认为 ISO-8859-1file -i logs/error.log在nginx.conf中加error_log /var/log/nginx/error.log warn;不指定编码由系统决定或用iconv转换iconv -f ISO-8859-1 -t UTF-8 logs/error.log实操心得add_header Content-Type必须加always参数否则 Nginx 对 304、404 等非 200 响应不会发送该 header浏览器就可能用默认编码通常是 ISO-8859-1解析导致乱码。5.3 路径与挂载类问题发生率 25%问题现象根本原因排查命令一键修复curl http://localhost/测试页面.html返回404 Not Found宿主机html/目录未被 Docker Desktop 共享docker exec my-nginx ls /usr/share/nginx/html在 Docker Desktop Settings → Resources → File Sharing 中添加项目所在目录curl http://localhost/测试页面.html返回403 Forbiddenhtml/目录权限为750其他用户other无读取权ls -ld html/chmod 755 html/目录和chmod 644 html/*.html文件修改nginx.conf后nginx -s reload失败挂载的nginx.conf是只读roNginx 无法重载docker exec my-nginx nginx -s reload启动时去掉:ro或改用docker cp替换docker cp nginx.conf my-nginx:/etc/nginx/nginx.conf docker exec my-nginx nginx -s reload实操心得docker exec my-nginx ls /usr/share/nginx/html是万能诊断命令它能直接告诉你“容器里到底有没有那个文件”。如果这里看不到测试页面.html那 100% 是挂载或共享问题不用往下查。5.4 进阶技巧如何在不重启容器的情况下热更新中文配置生产环境不可能每次改个location就重启容器。我的做法是配置文件热重载# 修改宿主机 nginx.conf 后执行 docker exec my-nginx nginx -t docker exec my-nginx nginx -s reload前提是nginx.conf挂载为可写去掉:ro且权限正确。HTML 文件热更新# 修改宿主机 html/ 下的文件Nginx 会自动读取无缓存 # 如需强制刷新浏览器缓存加时间戳 curl http://localhost:8080/测试页面.html?t$(date %s)日志实时追踪带中文# 在宿主机上直接 tail中文正常显示 tail -f logs/access.log # 如果终端显示乱码临时设置 locale export LANGC.UTF-8 tail -f logs/access.log这套组合拳让我在客户现场 5 分钟内完成配置调整和验证客户全程无感知。6. 总结与延伸这个方案还能怎么玩从单容器到集群的平滑演进写到这里你已经掌握了在 Docker 上跑一个真正“中文友好”的 Nginx 容器的全部核心技能。但技术的价值从来不止于解决眼前一个问题。我想分享两个延伸思考它们来自我最近做的两个真实项目或许能帮你把这套方案用得更深、更远。第一个延伸是关于配置管理的工业化。上面的方案适合单机开发和测试但如果团队有 10 个微服务每个都要配 Nginx手动维护 10 份nginx.conf是灾难。我们的解法是把nginx.conf模板化用envsubst注入环境变量。比如# nginx.conf.template upstream backend { server ${BACKEND_HOST}:${BACKEND_PORT}; } server { listen 80; location / { proxy_pass http://${BACKEND_HOST}:${BACKEND_PORT}; proxy_set_header Host $host; } }然后启动时docker run -d \ -e BACKEND_HOSTapi-service \ -e BACKEND_PORT8000 \ -v $(pwd)/nginx.conf.template:/etc/nginx/nginx.conf.template:ro \ nginx-zh:latest \ sh -c envsubst /etc/nginx/nginx.conf.template /etc/nginx/nginx.conf exec nginx -g daemon off;这样一份模板N 个环境配置即代码。第二个延伸是关于中文日志的可观测性升级。access.log里的中文路径很好但如果要做实时分析比如统计“北京”、“上海”等城市访问量用grep效率太低。我们的做法是用 Fluent Bit 把access.log采集到 ElasticsearchKibana 里直接用中文字段做可视化。关键配置是 Fluent Bit 的parser[PARSER] Name nginx_json Format regex Regex ^(?remote[^ ]*) - (?user[^ ]*) \[(?time[^\]]*)\] (?method\S)(?: (?path[^\]*?)(?: \S*)?)? (?code[^ ]*) (?size[^ ]*)(?: (?referer[^\]*) (?agent[^\]*)(?: (?http_x_forwarded_for[^ ]*))?)?$ Time_Key time Time_Format %d/%b/%