A complex user application that depends on a multitude of non-trivial syscalls cannot simply be recompiled for a bare-metal environment without some serious porting effort.
While newlib (though not newlib-nano) is reentrant, you would need to implement your own threading library to schedule threads in a bare-metal environment, which by definition lacks an OS to provide such services.
The Chipyard boot ROM redirects all harts to the same entry point, by default the start of main memory at 0x80000000. The startup code in the payload usually then reads hartid to identify which hart it is running on and decide how to proceed. If the number of software threads does not exceed the number of harts in the system, a thread pool approach that does not require preemptive multitasking could be feasible.
Multithreading is the least of the potential hurdles, however -- presumably, Nginx relies on some form of support for filesystem and networking I/O.
newlib factors out some of the platform-specific functionality into libgloss (essentially a board support package), which also must be modified. Since it makes very few assumptions about the execution environment except for the absence of an OS, the default RISC-V target mostly contains unimplemented stubs for a couple dozen syscalls:
I'm not sure if newlib actually supports a BSD-compatible sockets API. Even if that were the case, you would still need a TCP/IP stack and a NIC driver.
For applications that are heavily reliant on POSIX, by far the easiest option is to use the riscv64-unknown-linux-gnu toolchain with a GNU/Linux system.