nginx server 如何写,如何写 nginx 配置

本篇文章主要介绍 nginx server 虚拟服务器如何配置。其中包括的一些例子我会已保存到 nginx 。尽可能的想要整理一份比较完整的配置说明,避免找寻资料的麻烦。博主也尽可能的保证本篇文章的准确性,如有失误,请告知。

通过 $ nginx -V,你可以看到 nginx 的编译配置信息:

$ nginx -V
nginx version: nginx/1.17.3
built by gcc 8.3.0 (Debian 8.3.0-6)
built with OpenSSL 1.1.1c  28 May 2019
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads ...

其中可以看到 --prefix=/etc/nginx,nginx 安装时会把相关数据文件写入到该目录,如我们的配置文件 --conf-path

每次更改 nginx 的配置文件,你需要执行一下操作:

# 验证配置文件的正确性
$ nginx -T

# 重新加载配置文件
$ nginx -s reload

基础概念

这里推荐 nginx 的官方文档地址:http://nginx.org/en/docs/

文档中涵盖了各个模块的配置用法,以及默认值,可以填写的上下文位置。 nginx-module-doc

目前 nginx 支持多种服务类型:

http
mail
stream
google perftools

我们 着重介绍 http 服务。其它服务基本知识点都能涵盖到。

安装完 nginx ,我们先来看一看 nginx 的默认配置 /etc/nginx/nginx.conf,当然可能与你的默认配置不同,不过大同小异:

# worker以什么身份运行
user  nginx; // default nobody

# worker进程个数,一般为 CPU 个数,也可选 auto
worker_processes  1; # default 1

# 每个worker可打开的描述符限制
worker_rlimit_nofile 8192;

# 错误日志保存路径和级别
error_log  /var/log/nginx/error.log warn;

# 进程pid保存路径
pid        /var/run/nginx.pid;

# 指定dns服务器
resolver 10.0.0.1;

events {
    # 每个worker最大连接数
    worker_connections  1024; # default 1024
}

# http 服务定义
http {
    # 加载 mime 类型
    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"';
    # 访问日志
    access_log  /var/log/nginx/access.log  main;
    # 是否调用sendfile函数(zero copy 方式)来输出文件,如果磁盘IO重负载应用,可设置为off
    sendfile        on;
    # 此选项允许或禁止使用socke的TCP_CORK的选项,此选项仅在使用sendfile的时候使用
    #tcp_nopush     on;

    keepalive_timeout  65;

    # 代理相关设置
    # proxy_connect_timeout 90;
    # proxy_read_timeout 180;
    # proxy_send_timeout 180;
    # proxy_buffer_size 256k;
    # proxy_buffers 4 256k;
    # proxy_busy_buffers_size 256k;
    # proxy_temp_file_write_size 256k;

    # tcp_nodelay on;
    
    # gzip 压缩
    #gzip  on;

    # 加载其它配置,这样我们在 conf.d 下写的文件才会生效
    include /etc/nginx/conf.d/*.conf;
}

加载配置 /etc/nginx/conf.d,才能让我们的配置生效:

# 加载其它配置
include /etc/nginx/conf.d/*.conf;

一般的,如果是小站点不用去修改默认配置。当流量到达一定程度,需要进行适当优化。

内置变量

内置变量,nginx 各个模块都将请求的一些参数进行变量化,通过 $ + 变量名 即可使用。每个模块或多或少都有自己的变量。着重介绍下核心模块的 内置变量

# 通过arg_<name>的方式可取出相关参数,若请求 /foo?name=Tony&age=2,则 arg_name=tony arg_age=2
$arg_name
$args
# 客户端IP地址二进制
$binary_remote_addr
# 发送到客户端的字节数,不包括响应头
$body_bytes_sent
# 发送给客户端字节数
$bytes_sent
# 连接序列号
$connection
# 当前已经连接的请求书
$connection_requests
# Content-Length 请求头
$content_length
# Content-Type 请求头
$content_type
# cookie 名称
$cookie_name
# 当前请求的 root 或 alias 的值
$document_root
# 与 $uri 相同
$document_uri
# 优先级:请求行中的 host name,请求头中的 Host,请求匹配的 server name
$host
# host name
$hostname
# 任意请求头字段。变量名的最后一部分是转换为小写的字段名,用下划线替换破折号
$http_name
# 如果连接在 SSL 模式下运行,则为 on,否则为空字符串
$https
# ? 后如果请求行有参数,或者空字符串
$is_args
# 设置此变量可以限制响应速度
$limit_rate
# 当前时间(秒),分辨率为毫秒
$msec
# nginx 版本号
$nginx_version
# 当前 worker 进程号
$pid
# 如果是 pipelined 则为 p,否则为 . 
$pipe
# 代理协议头中的客户端地址,否则为空字符串,代理协议之前必须通过在listen指令中设置 proxy_protocol 参数来启用
$proxy_protocol_addr
# 来自代理协议头的客户端端口,否则为空字符串,代理协议之前必须通过在listen指令中设置 proxy_protocol 参数来启用
$proxy_protocol_port
# 与 $args 相同
$query_string
# 与当前请求的 root 或 alias 指令值对应的绝对路径名,所有符号链接都解析为实际路径
$realpath_root
# 客户端地址
$remote_addr
# 客户端端口
$remote_port
# 使用 Basic auth 的用户名
$remote_user
# 完整的请求行
$request
# 请求体,当将请求体读入内存缓冲区时,proxy_pass、fastcgi_pass、uwsgi_pass和scgi_pass指令处理的位置可以使用变量的值
$request_body
# 具有请求主体的临时文件的名称
$request_body_file
# 如果请求完成则为 OK,否则为空
$request_completion
# 当前请求的文件路径,基于 root 或 alias 和请求 URI
$request_filename
# 由16个随机字节生成的惟一请求标识符,以十六进制表示
$request_id
# 请求长度(包括请求行、头和请求体)
$request_length
# 请求方法,如 GET 或 POST
$request_method
# 请求处理时间,从客户端读取第一个字节以来的时间
$request_time
# 若请求 /foo?a=1&b=2,则 request_uri=/foo?a=1&b=2
$request_uri
# 如 http 或 https
$scheme
# 任意响应报头字段,变量名的最后一部分是转换为小写的字段名,用下划线替换破折号
$sent_http_name
# 响应结束时发送的任意字段,变量名的最后一部分是转换为小写的字段名,用下划线替换破折号
$sent_trailer_name
# 接受请求的服务器的地址
$server_addr
# 接受请求的 server 名称
$server_name
# 接受请求的 server 端口
$server_port
# 请求协议,如 HTTP/1.0 或 HTTP/1.1 或 HTTP/2.0
$server_protocol
# 响应状态
$status
$tcpinfo_rtt,$tcpinfo_rttvar,$tcpinfo_snd_cwnd,$tcpinfo_rcv_space
# 本地时间ISO 8601标准格式
$time_iso8601
# 通用日志格式的本地时间
$time_local
# 若请求 /foo?a=1&b=2,则 uri=/foo
$uri
# 用户代理
$http_user_agent
# cookie
$http_cookie

你还可以通过自定义变量指令 set 进行变量的定义。

server定义

server 即虚拟服务,它用来描述我们站点一些访问规则。需要填写在 http 标签中,可定义多个,如:

http {
    server {
        ...
    }
    server {
        ...
    }
    ...
}

一个常见的 server 的定义:

resolver 10.0.0.1;

# 负载均衡
upstream dynamic {    
    zone upstream_dynamic 64k;

    server backend1.example.com      weight=5;
    server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
    server 192.0.2.1                 max_fails=3;
    server backend3.example.com      resolve;
    server backend4.example.com      service=http resolve;

    server backup1.example.com:8080  backup;
    server backup2.example.com:8080  backup;
}

# http服务
server {
    listen 80;
    server_name example.com www.example.com;
    location / {
        rewrite https://$host; # 重定向到https
    }
}

# https 服务
server {
    listen 443 ssl; # 监听端口
    server_name example.com www.example.com; # 匹配域名

    # ssl证书
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
    ssl_certificate     /usr/local/nginx/conf/cert.pem;
    ssl_certificate_key /usr/local/nginx/conf/cert.key;
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 10m;

    # 静态服务
    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
    }
    # 反向代理
    location /api {
        proxy_pass http://dynamic;
        health_check;
    }
}

下面就让我们来详细解释下。

http_upstream_module

http_upstream_moduleupstream 说白了就是做负载均衡,它可以帮助我们定义一组相同服务的别名,如backend,当请求到来的时候可以通过相关策略帮我们选一组服务提供响应。

目前只能被 proxy_passfastcgi_passuwsgi_passscgi_passmemcached_passgrpc_pass 使用。

形式如下:

upstream <name> { # 命名
    server <address> [parameters]; # 服务
    server <address> [parameters];
    ...
}

[parameters] 参数可选以下值:

  • weight=number,default 1,设置 server 的权重
  • max_conns=number,default 0,限制 server 的活跃连接数,0 代表不限制
  • max_fails=number,default 1,设置在 fail_timeout 时间内失败的最大次数,可由 proxy_next_upstreamfastcgi_next_upstreamuwsgi_next_upstreamscgi_next_upstreammemcached_next_upstreamgrpc_next_upstream 指定下组 upstream,0 值代表不启用
  • fail_timeout=time,default 10s,设置多长时间判定无连接服务器失败
  • backup,标记 server 为备用 server,当 primary server 不可用时启用
  • down,标记 server 下线不可用
  • resolve,用来监视与服务器域名对应IP地址的更改,它会自动更改上游配置,upstream 必须驻留在共享内存中,必须写在 http 标签中。
http {
  resolver 10.0.0.1;

  upstream u {
    zone ...;
    ...
    server example.com resolve;
  }
}
  • route=string,设置 server 路由名称
  • server=name,
  • slow_start=time,慢启动,server 非正常状态恢复到正常需要的时间
  • drain,设置为 drain 模式

其它负载均衡设置:

  • zone name [size],设置共享内存的名称和大小
  • state file
  • hash key [consistent],负载均衡方式,key 可以为文本,变量,或其组合
  • ip_hash,负载均衡方式,根据IP地址范围分布 server,用 IPv4 前三个8位或整个IPv6
  • keepalive connections,设置到上游 server 保持最大空闲连接
upstream memcached_backend {
  server 127.0.0.1:11211;
  server 10.0.0.2:11211;

  keepalive 32;
}

server {
  ...

  location /memcached/ {
    set $memcached_key $uri;
    memcached_pass memcached_backend;
  }
}
  • keepalive_requests number,设置最大请求连接数
  • keepalive_timeout timeout,连接超时时间
  • ntlm,允许使用NTLM身份验证代理请求
upstream http_backend {
  server 127.0.0.1:8080;

  ntlm;
}

server {
  ...

  location /http/ {
    proxy_pass http://http_backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    ...
  }
}
  • least_conn,负载均衡方式,将请求传给活跃连接数最少的 server
  • least_time header | last_byte [inflight],负载均衡方式,将请求传给平均响应时间和活跃连接数最少的 server
  • queue number [timeout=time],队列缓存,当选择不到 server 处理请求时放入队列,如果队列满,返回502
  • random [two [method]],负载均衡方式,
  • sticky,会话关联,同一客户端请求将会被传给同一 upstream 的同一 server
  # cookie
  upstream backend {
    server backend1.example.com route=a;
    server backend2.example.com route=b;

    sticky cookie srv_id expires=1h domain=.example.com path=/;
  }
  # route
  map $cookie_jsessionid $route_cookie {
    ~.+\.(?P<route>\w+)$ $route;
  }

  map $request_uri $route_uri {
    ~jsessionid=.+\.(?P<route>\w+)$ $route;
  }

  upstream backend {
    server backend1.example.com route=a;
    server backend2.example.com route=b;

    sticky route $route_cookie $route_uri;
  }
  # learn
  upstream backend {
    server backend1.example.com:8080;
    server backend2.example.com:8081;

    sticky learn
      create=$upstream_cookie_examplecookie
      lookup=$cookie_examplecookie
      zone=client_sessions:1m;
  }

listen

listen 监听设置,来看一看可选参数:

默认 listen *:80 | *:8000;
listen address[:port] [default_server] [ssl] [http2 | spdy] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
listen port [default_server] [ssl] [http2 | spdy] [proxy_protocol] [setfib=number] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
listen unix:path [default_server] [ssl] [http2 | spdy] [proxy_protocol] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];

真的多,可平时也没用几个,举例:

listen 127.0.0.1:8000;
listen 127.0.0.1; # 如果只指定地址,默认监听 80
listen 8000;
listen *:8000;
listen localhost:8000;
listen 127.0.0.1 default_server accept_filter=dataready backlog=1024;

# IPv6
listen [::]:8000;
listen [::1];

# unix socket
listen unix:/var/run/nginx.sock;

其它参数说明:

  • default_server,如果指定,server 将会成为默认 server
  • ssl,开启 ssl 模式,即 https
  • http2,正常情况开启 http2 都应该开始 ssl,但 nginx 也支持不开启 ssl 下的 http2 协议
  • spdy,和 http2 一样,建议开启 ssl
  • setfib=number,监听套接字设置关联的路由表FIB (SO_SETFIB选项)。这目前只适用于FreeBSD
  • fastopen=number,为监听套接字启用“TCP Fast Open”(1.5.8),并限制尚未完成三方握手的连接队列的最大长度
  • backlog=number
  • rcvbuf=size,接受 buffer 的大小(SO_CRCVBUF)
  • sndbuf=size,发送 buffer 的大小(SO_SNDBUF)
  • accept_filter=filter,可选 dataready 和 httpready,在 accept() 前过滤
  • deferred,指示在Linux上使用deferred accept() (TCP_DEFER_ACCEPT套接字选项)
  • bind,标记指定 address:port 单独的绑定
  • ipv6only on|off,只接受 IPv6 连接
  • reuseport
  • so_keepaliv on|off|[keepidle]:[keepintv1]:[keepcnt],”TCP keepalive” 开关

server_name

server_name,设置虚拟主机的名称。

形式如下:

默认值 server_name "";
server_name name ...;

例1,穷举域名

server {
    server_name example.com www.example.com;
}

例2,通配符写法

server {
    server_name example.com *.example.com www.example.*;
}

例3,这种写法满足例1

server {
    server_name .example.com;
}

例4,正则表达式,以 ~ 开头

server {
    server_name www.example.com ~^www\d+\.example\.com$;
}

例5,正则表达式捕获

server {
    server_name ~^(www\.)?(.+)$;

    location / {
        root /sites/$2;
    }
}

server {
    server_name _;

    location / {
        root /sites/default;
    }
}

例6,正则表达式变量

server {
    server_name ~^(www\.)?(?<domain>.+)$;

    location / {
        root /sites/$domain;
    }
}

server {
    server_name _;

    location / {
        root /sites/default;
    }
}

例7,与空名称使用

server {
    server_name www.example.com "";
}

如果当一个名称匹配多个 server 的是时候,匹配优先级如下:

  1. 确切的名称
  2. 以 * 开头的最长的通配符名称
  3. 以 * 结尾的最长通配符名称
  4. 第一个匹配的正则表达式

更多匹配规则请查阅:http://nginx.org/en/docs/http/server_names.html

location

location 是用来干嘛的,它是用来根据 URI 进行配置设置的,如:

server {
    listen 80;
    server_name example.com;

    location / { # 普通请求网页
        root /usr/share/nginx/html;
        index index.html index.htm;
    }

    location /api { # API请求代理
        proxy_pass http://dynamic;
        health_check;
    }
}

形式如下:

location [ = | ~ | ~* | ^~ ] uri { ... }
  • none,如果没有修饰符,则将该位置解释为前缀匹配。这意味着给定的位置将根据请求URI的开头进行匹配,以确定匹配
  • =,代表精确匹配,完全相等即匹配
  • ~,区分大小写的正则表达式匹配
  • ~*,不区分大小写的正则表达式匹配
  • ^~,普通字符匹配,如果该选项匹配,只匹配该选项

nginx 的匹配过程如下:

  1. 精确匹配 =,如果匹配成功,搜索停止
  2. 前缀匹配,最长位置匹配,如果该匹配具有 ^~,搜索停止
  3. 正则匹配,按配置文件中定义的顺序进行匹配。
  4. 如果第3条规则产生匹配的话,结果被使用。否则,使用第2条规则的结果。

让我们通过一个例子来了解下匹配规则:

location = / {
    [ configuration A ]
}

location / {
    [ configuration B ]
}

location /documents/ {
    [ configuration C ]
}

location ^~ /images/ {
    [ configuration D ]
}

location ~* \.(gif|jpg|jpeg)$ {
    [ configuration E ]
}

请求 / 将会匹配 A,请求 /index.html 将会匹配 B,请求 /documents/document.html 将会匹配 C,请求 /images/1.gif 将会匹配 D,请求 /documents/1.jpg 将会匹配 E。

ssl mode

ssl 模式可以让我们站点启用 HTTPS,具体详细请参考 http_ssl_module

想要开启 ssl 模式,需要在 listen 关键字处添加上 ssl,如:

server {
    listen              443 ssl;
    server_name         example.com;

    ssl_certificate     example.com.rsa.crt;
    ssl_certificate_key example.com.rsa.key;

    ssl_certificate     example.com.ecdsa.crt;
    ssl_certificate_key example.com.ecdsa.key;

    ...
}

上面的例子是部署双证书,当某一证书因某种原因失效不至于导致站点不能访问。下面来看看参数解释:

  • ssl_buffer_size size,default 16k,发送数据的缓冲区的大小
  • ssl_certificate file,PEM 格式证书文件
  • ssl_certificate_key file,PEM 格式私钥文件
  • ssl_ciphers ciphers,default HIGH:!aNULL:!MD5,ssl套件 openssl ciphers
  • ssl_client_certificate file,用于验证客户端证书的 CA 文件
  • ssl_crl file,用于验证客户端证书的吊销文件
  • ssl_dhparam file,为DHE密码指定具有DH参数的文件
  • ssl_early_data on|off,default on
  • ssl_ecdh_curve curve,default auto,为ECDHE密码指定一条曲线
  • ssl_password_file file,私钥密码文件
  • ssl_prefer_server_ciphers on|off,是否启用服务器套件偏好
  • ssl_protocols [SSLv2] [SSLv3] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3],default TLSv1 TLSv1.1 TLSv1.2,可选的ssl协议
  • ssl_session_cache off|none|[builtin[:size]] [shared:name:size],default none,设置 session cache 的类型和大小
ssl_session_cache builtin:1000 shared:SSL:10m;
  • ssl_session_ticket_key file,设置一个文件,其中包含用于加密和解密TLS会话票据的密钥
ssl_session_ticket_key current.key;
ssl_session_ticket_key previous.key;

随机一个 AES256(80),AES128(40)
openssl rand 80 > ticket.key
  • ssl_session_tickets on|off,default on,是否启用 session ticket
  • ssl_session_timeout time,default 5m,超时时间
  • ssl_stapling on|off,default off,ocsp 装订 ssl_stapling on; resolver 192.0.2.1;
  • ssl_stapling_file file
  • ssl_stapling_responder url
  • ssl_stapling_verify on|off,default off
  • ssl_trusted_certificate file,指定验证客户端证书的 CA 文件
  • ssl_verify_client on|off|optional|optional_no_ca,default off,是否验证客户端证书
  • ssl_verify_depth number,default 1,设置客户端证书链的验证深度

相关变量

$ssl_cipher,已建立连接使用的 ciphers
$ssl_ciphers,客户端支持的 ciphers
$ssl_client_escaped_cert,urlencoded 客户端证书
$ssl_client_fingerprint,SHA1指纹
$ssl_client_i_dn,issuer DN
$ssl_client_i_dn_legacy,同上,1.11.6之后使用
$ssl_client_raw_cert,PEM格式客户端证书
$ssl_client_s_dn,subject DN
$ssl_client_s_dn_legacy,同上,1.11.6之后使用
$ssl_client_serial,客户端证书序列号
$ssl_client_v_end,客户端证书结束时间
$ssl_client_v_remain,剩余多少天
$ssl_client_v_start,证书开始时间
$ssl_client_verify,客户端证书是否验证成功,"SUCCESS" 或 "FAILED:reason" 或 "NONE"
$ssl_curves,客户端支持的曲线
$ssl_early_data
$ssl_protocol,连接使用的协议
$ssl_server_name,从 SNI 获取的 server name
$ssl_session_id,连接的 session id
$ssl_session_reused,session是否重用,"r" 重用,"." 没有

其它模块

其它模块你需要根据文档及编译信息判断该模块是否默认编译在 nginx 中,并且版本是否匹配:

ngx_http_access_module
ngx_http_addition_module
ngx_http_api_module
ngx_http_auth_basic_module
ngx_http_auth_jwt_module
ngx_http_auth_request_module
ngx_http_autoindex_module
ngx_http_browser_module
ngx_http_charset_module
ngx_http_dav_module
ngx_http_empty_gif_module
ngx_http_f4f_module
ngx_http_fastcgi_module
ngx_http_flv_module
ngx_http_geo_module
ngx_http_geoip_module
ngx_http_grpc_module
ngx_http_gunzip_module
ngx_http_gzip_module
ngx_http_gzip_static_module
ngx_http_headers_module
ngx_http_hls_module
ngx_http_image_filter_module
ngx_http_index_module
ngx_http_js_module
ngx_http_keyval_module
ngx_http_limit_conn_module
ngx_http_limit_req_module
ngx_http_log_module
ngx_http_map_module
ngx_http_memcached_module
ngx_http_mirror_module
ngx_http_mp4_module
ngx_http_perl_module
ngx_http_proxy_module
ngx_http_random_index_module
ngx_http_realip_module
ngx_http_referer_module
ngx_http_rewrite_module
ngx_http_scgi_module
ngx_http_secure_link_module
ngx_http_session_log_module
ngx_http_slice_module
ngx_http_spdy_module
ngx_http_split_clients_module
ngx_http_ssi_module
ngx_http_ssl_module
ngx_http_status_module
ngx_http_stub_status_module
ngx_http_sub_module
ngx_http_upstream_module
ngx_http_upstream_conf_module
ngx_http_upstream_hc_module
ngx_http_userid_module
ngx_http_uwsgi_module
ngx_http_v2_module
ngx_http_xslt_module

nginx完整配置

一份给新人的 nginx 完整配置:https://github.com/deepzz0/nginx

参考链接

[1] http://nginx.org/en/docs/

本文链接:参与评论 »

--EOF--

提醒:本文最后更新于 1937 天前,文中所描述的信息可能已发生改变,请谨慎使用。

Comments