Nginx 使用

配置文件

全局配置部分

user www www;
worker_process 2;

error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

pid  logs/nginx.pid

events {
  use epoll;
  worker_connections 2048;
}

http {
    ...
    server {
    
    }
}
  • user www www

nginx 的运行用户和组。

  • worker_process 2

再配置文件的顶级 main 部分,表示 worker 角色的工作进程的个数。nginx 进程分为 master 和 worker。master负责接收并分配请求给 worker 处理。这个数值可以简单设置为 cpu 的核数 grep ^processor /proc/cpuinfo | wc -l, 也即是 auto 值。如果开启了 ssl 和 gzip 更应该设置成于逻辑 cpu 数目一样或者 2 倍,可以减少 io 操作。如果 nginx 服务器上还有其他服务,可以适当减少。

  • worker_cpu_affinity

也是写在 main 部分。在高并发情况下,通过设置 cpu 粘性来降低由于多 cpu 核切换造成的寄存器等线程重建带来的性能损耗。如 worker_cpu_affinity 0001 0010 0100 1000 (四核)。、

  • worker_rlimit_nofile 10240

写在 main 部分,默认没有设置,可以限制为操作系统最大的限制65535。

  • worker_connections 2048

写在 event 部分,每一个 worker进程能够并发处理(发起)的最大连接数(包含与客户端或后端被代理服务器的连接)。Nginx 作为反向代理服务器时,最大连接数 = worker_processes * worker_connections/4,所以这里客户端最大连接数是 1024,这个可以增大到 8192,看情况而定。但不能超过上面的 worker_rlimit_nofile。当 nginx 作为 http 服务器时,最大连接数计算公式里是除以2。

http 服务器部分

http {
  include mime.types;
  default_type application/octet-stream;
  # log_format main '$remote_addr - $remote_user [$time_local] "$request"'
  #  '#$datatus $body_bytes_sent "$http_refer"'
  #  '"$http_user_agent" "$http_x_forwarded_for"'
  
  #access_log logs/access_log main;
  sendfile on;
  # tcp_nopush on;
  keepalive_timeout 65;
  
  # gzip 压缩功能设置
  gzip on;
  gzip_min_length 1k;
  gzip_buffers 4 16k;
  gzip_http_version 1.0;
  gzip_comp_level 6;
  gzip_types text/html text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
  gzip_vary on;
  
  # http proxy 设置  
  client_max_body_size 10m;
  client_body_buffer_size 128k;
  proxy_connect_timeout 75;
  proxy_send_timeout 75;
  proxy_read_timeout 75;
  proxy_buffer_size 4k;
  proxy_buffers 4 32k;
  proxy_busy_buffers_size 64k;
  proxy_temp_file_write_size 64k;
  proxy_temp_path /usr/local/nginx/proxy_temp 1 2;
  
  upstream backend {
  
  }
  
  server {
  
  }
}
  • sendfile on

开启搞笑文件传输模式。sendfile 指令指定 nginx

是否调用 sendfile 函数来输出文件,减少用户空间到内核空间的上下文切换。对于普通应用设为 on,如果用来进行下载等磁盘IO重负载应用,可以设置为 off,以平衡磁盘与网络IO处理速度,降低系统的负载。

  • keepalive_timeout 65

长连接超时时间,单位是秒。这个参数很敏感,设计浏览器的种类,后端服务的超时设置,操作系统的超时设置。长连接请求大量小文件的时候,可以减少重建连接的开销,但假如有大文件上传,65s 内没有上传完成会导致失败。如果设置时间过长,用户又多,长时间保持连接会占用大量资源。

  • send_timeout

用于指定相应客户端的超时时间。这个超时仅限于两个连接活动之间的时间,如果超过这个时间,客户端没有任何活动,nginx 就关闭连接。

  • client_max_body_size 10m;

允许客户端请求的最大单文件字节数。如有上传较大文件,需要设置这个值。

  • client_body_buffer_size 128k;

缓冲区代理缓冲用户端请求的最大字节数。

gzip 模块

  • gzip on;

开启 gzip 压缩输出,减少网络传输。

  • gzip_min_length 1k;

设置允许压缩的压面最小字节数,页面字节数从 header 头的 content-length 中进行获取。默认值是 20。建议设置成大于 1k 的字节数,小于 1k 可能越压越大。

  • gzip_buffers 4 16k;

设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流。4 16k 代表以16k为单位,按照原始数据的大小以 16k 为单位的4倍申请内存。

  • gzip_http_version 1.0;

用于识别 http 协议的版本。早期的浏览器不支持 gzip 压缩,用户就会看到乱码,为了支持早期版本加上了这个参数。

  • gzip_copm_level 6;

gzip 压缩比,1压缩比最小处理速度最快,9压缩比最大但处理速度最慢(传输快但比较消耗cpu)

  • gzip_types

匹配 mime 类型进行压缩,无论是否制定,text/html 类型总是会被压缩的。

  • gzip_proxied any

Nginx 作为反向代理的时候启用,决定开启或者关闭后端服务器返回的结果是否压缩,匹配的前提是后端服务器必须要返回包含 ‘Via’ 的 header 头。

  • gzip_vary on

和 http 头有关系,会在响应加个 ‘Vary: Accept-Encoding’,可以让前端的缓存服务器缓存经过 gzip 压缩的压面。例如用过 squid 缓存经过 nginx 压缩的数据。

http proxy 模块

  • proxy_connect_timeout 60;

nginx 跟后端服务器连接超时时间(代理连接超时)

  • proxy_read_timeout 60;

连接成功后,与后端服务器两个成功的响应操作之间超时时间(代理接收超时)

  • proxy_buffer_size 4k;

设置代理服务器(nginx)从后端 real server 读取并保存用户头信息的缓冲区大小,默认与 proxy_buffers 大小相同。其实可以将这个指令值设的小一点。

  • proxy_buffers 4 32k

proxy_buffers 缓冲区,nginx 针对单个连接缓存来自后端 real server 的响应,网页平均在 32k 以下的话这样设置。

  • proxy_busy_buffers_size 64k;

高负荷下缓冲大小(proxy_buffers * 2)

  • proxy_max_temp_file_size

当 proxy_buffers 放不下后端服务器的响应内容时,会将一部分保存到硬盘的临时文件中,这个值用来设置最大临时文件的大小,默认为 1024m,它与 proxy_cache 没有关系。大于这个值,将从 upstream 服务器传回。设置 0 为禁用。

  • proxy_temp_file_write_size 64k;

当缓存被代理服务器的响应到临时文件时,这个选项限制每次写临时文件的大小。

  • proxy_temp_path

指定临时文件在哪个目录

server 虚拟主机部分

upstream backend {
  server 192.168.10.100:8080 max_fails=2 fail_timeout=30s;
  server 192.168.10.101:8080 max_fails=2 fail_timeout=30s;
}

server {
  listen 80;
  server_name laily.net;
  root /apps/aapp;
  
  charset utf-8;
  access_log logs/host.access.log main;
  
  # 对 / 反向代理
  location / {
    root /apps/aapp;
    index index.html;
    proxy_pass http://backend;
    
    proxy_redirect off;
    # 后端服务器通过 x-forwarded-for 获取用户的真实 ip
    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_next_upstream eror timeout invalid_header http_500 http_502 http_503 http_504;  
  }
  
  # 静态文件,nginx 自己处理
  location ~* /download/ {
    root /apps/file;
  }
  location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ {
   root /apps/aapp/static;
   expires 7d;
  }
  location /nginx_status {
    stub_status on;
    access_log off;
    allow 192.168.10.0/24;
    deny all;
  }
  error_page 500 502 503 504 /50x.html;
  location = /50x.html {
    root html;
  }
}

http 服务商支持若干个虚拟主机。每个虚拟主机对应一个 server 配置项。

  • listen

监听端口,默认 80,小鱼 1024 需要以 root 身份启动。可以为 listen *:80listen 127.0.0.1:80 等形式

  • server_name

服务器名,如 www.aa.com,localhost,可以通过正则表达式。

http_stream 模块

这个模块通过一个简单的调度算法来实现客户端 ip 到后端服务器的负载均衡, upstream 后接负载均衡器的名字,后端 real server 以 host:port options 的方式组织在 {} 中。

location

  • root /var/www/html

定义服务器默认网站根目录地址。如果 location URL 匹配的是子目录或者文件,root 没什么用。一般放在 server 指令或者 / 下。

  • index index.html

定义路径下默认的访问文件名,一般跟着 root 放。

  • proxy_pass http://backend

请求转向 backend 定义的服务器列表,即反向代理,对应 upstream 负载均衡器。也可以 proxy_pass http://ip:port。

  • proxy 选项

proxy_redirect off;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

暂且这样设置,每个都涉及很多内容。

访问控制

使用多个 allow,deny,允许某个或禁止某个 ip,ip段的访问,依次匹配,满足任何一个规则就停止往下匹配。

autoindex

nginx 默认不允许列出整个目录。如果需要整个功能,就在配置文件的 location, server 或 http 段中加入 autoindex on; 一般也把下面两个配置加上。

  • autoindex_exact_size off;

默认为 on,显示出文件的确切大小,单位是 bytes。改为 off 后,显示出文件的大概大小,单位是 kb,mb 或者 gb。

  • autoindex_localtime on;

默认为 off,显示文件时间为 GMT时间。改为 on 后,显示服务器时间。

参考:

http://seanlook.com/2015/05/17/nginx-install-and-config/

配置 location, rewrite

一个简单的 nginx 配置

...
events {
  # 模式配置
}

http {
  # 默认配置
   server {
     # 虚拟主机1
     listen 80 default_server;
     server_name example1.com www.example1.com;
     ...
   }
   
   server {
     # 虚拟主机2
     listen 8080;
     server_name example2.com;
     ...
   }
   server {
     # 虚拟主机3
     listen 80;
     server_name example3.com
   }
   
}

一个请求访问到服务器,nginx 根据 url 中的 host 部分,匹配到某一个虚拟主机。

default_server 表示默认虚拟主机,如果没有指定,则第一个 server 配置会被认为是默认虚拟主机。

location 配置

一个 location 表示一个url 规则。

location 语法

location 前缀 匹配字符 {具体配置}

前缀有这几种: =(全匹配), ~(正则匹配,区分大小写), *(正则匹配,不区分大小写), ^(路径匹配) 或者为空(字符串匹配)。

匹配的优先级:

全匹配 -> 路径匹配 -> 正则匹配 -> 字符串匹配(前缀为空)

rewrite 配置

rewrite 语法

rewrite regex replacement [flag]

其中 regex 是正则表达式,replacement 是要重定向的字符串, flag 是标识。

比如

rewrite ^/cms/(.*).php$ /cms/index.php break;

含义:访问 /cms/xxx.php 重定向到 /cms/index.php

rewrite 可以写在 location 里,也可以写在 server 里。

rewrite 的 flag 标记

break 表示完成当前的 rewrite

last 表示完成当前的 rewrite,然后查找匹配改变后的新 location

redirect 在 replacement 字符串未以 “http://” 或者 “https://” 开头时,使用返回状态码为 302 的临时重定向。

permanent 返回状态码为 301 的永久重定向

redirect 和 permanect 会修改用户访问的 url。

break 和 last 是 nginx 内部的重定向。

nginx rewrite log 调试

需要检查 nginx 到底匹配了哪条 location/rewrite,就需要打开 rewrite log,

开启方法,在 http 段加上

rewrite_log on;
# error log 需要改成 notice 级别

location 示例

# 文件和目录不存在时,重定向到某个文件
if (!-e $request_filename) {
    rewrite ^/(.*)$ index.html last;
}

# 禁止访问指定后缀的文件
location ~ /(\.ht|\.git|\.snv) {
  deny all;
  break;
}

# 设置某些类型文件的浏览器缓存时间
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
  expires 30d;
}

location ~ .*\.(js|css)$ {
 expires 1h;
}

# 目录自动添加 /
if (-d $request_filename) {
  rewrite ^/(.*)([^/])$ http://$host/$1$2/ premanent;
}

# 只允许固定 ip 访问,并添加访问密码
root /opt/www
allow 208.97.167.19;
allow 222.333.11.22;
deny all;
auth_basic "admin";
auth_basic_user_file aaa;

全局变量

$args #这个变量等于请求行中的参数。 
$content_length #请求头中的Content-length字段。 
$content_type #请求头中的Content-Type字段。 
$document_root #当前请求在root指令中指定的值。
$host #请求主机头字段,否则为服务器名称。
$http_user_agent #客户端agent信息
$http_cookie #客户端cookie信息
$limit_rate #这个变量可以限制连接速率。
$request_body_file #客户端请求主体信息的临时文件名。
$request_method #客户端请求的动作,通常为GET或POST。
$remote_addr #客户端的IP地址。
$remote_port #客户端的端口。
$remote_user #已经经过Auth Basic Module验证的用户名。
$request_filename #当前请求的文件路径,由root或alias指令与URI请求生成。
$query_string #与$args相同。
$scheme #HTTP方法(如http,https)。
$server_protocol #请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
$server_addr #服务器地址,在完成一次系统调用后可以确定这个值。
$server_name #服务器名称。
$server_port #请求到达服务器的端口号。
$request_uri #包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
$uri #不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。
$document_uri #与$uri相同。

例如请求 http://localhost:88/test1/test2/test.php

各变量值如下:

$hostlocalhost
$server_port88
$request_urihttp://localhost:88/test1/test2/test.php
$document_uri/test1/test2/test.php
$document_rootD:\nginx/html
$request_filenameD:\nginx/html/test1/test2/test.php

配置 LDAP 认证

安装依赖

这个模块依赖于 nginx 的 http_auth_request_module 模块,没有安装的需要安装。

需要 python2 支持。

需要安装 python 的 python-ldap 模块。

安装 python-ldap 容易出错,原因是 python-ldap 是基于 OpenLDAP 的,需要先安装 OpenLDAP 相关的包

# ubuntu
apt-get install libsasl2-dev python-dev libldap2-dev libssl-dev
# centos
yum install openldap
yum install openldap24-libs
yum install openldap-clients
yum install openldap-devel
yum install openssl-devel

获取 nginx-ldap-auth 仓库

git clone https://github.com/nginxinc/nginx-ldap-auth.git

配置 nginx

在上面克隆的仓库里能看到 nginx 验证部分的配置,这里有一份简单点的配置。

# http 指令里配置
# 缓存可以减少ldap验证频率,不然每个页面都需要ldap验证一次
proxy_cache_path cache/ keys_zone=auth_cache:10m;

# server 里配置
 #后端程序
    location / {
        auth_request /auth-proxy;

        #nginx接收到nginx-ldap-auth-daemon.py返回的401和403都会重新跳转到登录页面
        error_page 401 403 =200 /login;

        后端程序
        proxy_pass http://127.0.0.1:1000/;
    }

 #登录页面,由backend-sample-app.py提供,跑在同一台机器的8082端口(默认不是8082端口)
    location /login {
        proxy_pass http://127.0.0.1:8082/login;
        proxy_set_header X-Target $request_uri;
    }

    location = /auth-proxy {
        internal;
        proxy_pass http://127.0.0.1:8888;     #nginx-ldap-auth-daemon.py运行端口
        #缓存设置
        proxy_cache auth_cache;
        proxy_cache_key "$http_authorization$cookie_nginxauth";
        proxy_cache_valid 200 403 10m;
        
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";

        # 最最重要的ldap配置,请务必按照贵公司的ldap配置如下四项,我在这一步卡了好久,就是ldap配置不对
        # 这些配置都会通过http头部传递给nginx-ldap-auth-daemon.py脚本
        proxy_set_header X-Ldap-URL      "ldap://ip:port";
        proxy_set_header X-Ldap-BaseDN   "DC=example,DC=com";
        proxy_set_header X-Ldap-BindDN   "cn=Admin,ou=People,dc=example,dc=com";
        proxy_set_header X-Ldap-BindPass "password";

        proxy_set_header X-CookieName "nginxauth";
        proxy_set_header Cookie nginxauth=$cookie_nginxauth;
    }

启动相关服务

然后启动 nginx-ldap-auth 目录里的 nginx-ldap-auth-daemon.py, backend-sample-app.py ,注意调整好端口。

启动 nginx-ldap-auth-daemon.py 报错

启动 nginx-ldap-auth-daemon.py 时报错 ImportError: No module named pyasn1.error

执行下面的命令解决

$ sudo pip install --upgrade pip
$ sudo pip install awscli --ignore-installed six
# thon-ldap 缺少这个依赖,而且需要版本号大于 0.1.5
$ sudo pip install pyasn1_modules==0.1.5

然后登录就会出现一个输入框需要输入账户和密码。

不过这里我发现除了设置 cookies 以外,还使用了 http 的 basic 验证。

https 配置证书

listen 443 ssl;
listen [::]:443 ssl ipv6only=on;

server_name example.com;

ssl on;
ssl_certificate /etc/ssl/private/example_com.crt;
ssl_certificate_key /etc/ssl/private/example_com.key;

nginx 强制跳转 https

server {
    listen 192.168.1.111:80;
    server_name test.com;
    rewrite ^(.*)$ <https://$host$1> permanent;
}

去掉 www

server {
    listen 443;
    server_name www.aaa.com
    return 301 https://aaa.com$request_uri;
}

独立出证书部分配置新建立一个文件

比如 /etc/nginx/conf.d/ssl-params.conf 说明见 https://godruoyi.com/posts/best-nginx-configuration-for-improved-security

server_tokens   off;

ssl_session_cache        shared:SSL:10m;
ssl_session_timeout      60m;

ssl_session_tickets      on;

ssl_stapling             on;
ssl_stapling_verify      on;

resolver                 8.8.4.4 8.8.8.8  valid=300s;
resolver_timeout         10s;
ssl_prefer_server_ciphers on;

# 证书路径 绝对地址
ssl_certificate          /etc/nginx/ssl/fullchain.cer;
ssl_certificate_key      /etc/nginx/ssl/godruoyi.key;

ssl_protocols            TLSv1 TLSv1.1 TLSv1.2;

ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

add_header Strict-Transport-Security "max-age=31536000;includeSubDomains;preload";
add_header  X-Frame-Options  deny;
add_header  X-Content-Type-Options  nosniff;
add_header x-xss-protection "1; mode=block";
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: https:; connect-src 'self' https:; img-src 'self' data: https: blob:; style-src 'unsafe-inline' https:; font-src https:";

然后配置 server 部分

server {
    listen 443 ssl http2 fastopen=3 reuseport default_server;
    listen [::]:443 ssl http2 fastopen=3 reuseport default_server;

    server_name www.aaa.com aaa.com;

    # 引入 SSL 配置
    include conf.d/ssl-params.conf;

    root /home/bot/xxx/;

    index index.php;
}

从静态 json 文件中响应 json 数据

location /get_data/ {
    default_type application/json;
    // index abc.json
    alias /home/bot/mydata/;
}

这个时候如果访问 /get_data/aaa/bbb.json 就会去 /home/bot/mydata/aaa/bbb.json 文件去读取数据并返回。

也可以在上面加上 index xxx.json,这样可以相当于指定一个默认 json 文件。

配置中的 alias 和 root

root

root 是当前代理项目的 rul 的相对路径。

location /a/b/ {
    root /c/d/e/;
}

实际的访问路径 /a/b/c/d/e/

alias

alias 是绝对路径

location /a/b/ {
    root /c/d/e/;
}

实际访问的是 /c/d/e

配置跨域请求

当出现 403 跨域错误时“No ‘Access-Control-Allow-Origin’ header is present on the requested resource”,需要给 Nginx 配置响应的 header 参数。

解决方案

只需要在 Nginx 配置中配置以下参数

locaction / {
    add_header Access-Control-Allow-Origin: *;
    add_header Access-Control-Allow-Methods: 'GET, POST, OPTIONS';
    add_header Access-Control-Allow-Headers: 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

    if ($request_method = "OPTIONS"){
        return 204;
    }
}

解释

  • Access-Control-Allow-Origin

服务器默认是不被允许跨域的。配置 Access-Control-Allow-Origin *后,表示允许所有的跨域请求。*处也可以填单个域名,比如http://example.com。如果要支持多个域名就需要用另外的方法了。

  • Access-Control-Allow-Headers

这个参数是为了防止以下错误 Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.。这个错误表示当前请求的 Content-Type 不被支持。设置这个于后面的预检请求有关。

  • Access-Control-Allow-Methods

设置允许的请求方法。

  • OPTIONS 的 204 返回

跨域时发送预检请求时,会使用 OPTIONS 方法,需要支持。

预检请求

CORS 全称为 Cross-Origin Resource Sharing 是专门为了解决跨域请求提出的。这个标准新增了一组 http header 字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 http 请求方法(Get 以外的请求,搭配某些 MIME 的 post 请求),浏览器必须先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务器是否允许该跨域请求。服务器确认允许后,才发起实际的 http 请求。在预检请求的返回中,服务端也可以通知客户端是否需要携带身份凭证(Cookies 或者 http 认证数据)。

参考

Nginx配置跨域请求 Access-Control-Allow-Origin

反向代理后的 Cookie 问题

比如有一个 a.com 服务,现在通过 nginx (b.com) 搭建了反向代理。

location /api {
   proxy_pass https://a.com;
}       

如果 a.com 这个服务设置 cookie 的时候指定了域名 a.com,那么通过 b.com 访问的时候并不会主动带上这个域名,因为域名注册在 a.com 上,会导致访问失败。

这种情况下可以加上 proxy_cookie_domain 指令用来修改注册 cookie 的域名。同样的还有 proxy_cookie_path 指令。

location /api {
   proxy_pass https://a.com;
   proxy_cookie_domain a.com  b.com;
}     

反向代理

  location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version  1.1;
    proxy_cache_bypass  $http_upgrade;

    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_set_header X-Forwarded-Host  $host;
    proxy_set_header X-Forwarded-Port  $server_port;
    proxy_set_header REMOTE-HOST $remote_addr;
  }

示例

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}