To those for whom none of the other answers have painted the full picture, I want to offer my own.
On Linux there is the IPV6_V6ONLY option/flag (see e.g. man ipv6) that can be set on sockets. The option is set/cleared with the setsockopt system function. By default the state of the flag matches the contents of the /proc/sys/net/ipv6/bindv6only file (0 for cleared aka not-only-IPv6, 1 for set aka only-IPv6).
Nginx leverages said option, which it explicitly sets (overriding system default) so that listen [::]:<port> (with <port> being a port number) is equivalent to listen [::]:<port> ipv6only=on which will create an [IPv6] socket that does not accept IPv4 connections.
When you want to support both versions of the IP protocol, the above implication can be mitigated using at least two solutions.
The first is to just have Nginx listen on two distinct sockets explicitly, having a listen *:<port> directive (* is an IPv4 address wildcard, never IPv6) in addition to the aforementioned listen directive, e.g. using port 80:
listen *:80;
listen [::]:80;
The second solution will create a single socket for which the IPV6_V6ONLY option is cleared by Nginx. The socket will accept both IPv4 and IPv6 connections. One single listen directive is sufficient for this, e.g. with port 80 again:
listen [::]:80 ipv6only=off;
The lsof program can be used to see how many sockets a process has, below assuming some process with PID 555:
lsof -a -p 555 -i -T f
(the -p 555 is for listing sockets of process with PID 555, the -i for listing Internet sockets (IPv4 and/or IPv6), the -P for printing port numbers instead of their names, and the -T f for listing additional information for each record, like the listening state of the socket; the -a is for making it an "and" query -- all of the predicates must be true for lsof to list a record; to that end the switch works much like the -and for find)