2 * nghttp2 - HTTP/2 C Library
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include <sys/types.h>
30 #ifdef HAVE_SYS_SOCKET_H
31 # include <sys/socket.h>
32 #endif // HAVE_SYS_SOCKET_H
36 #endif // HAVE_NETDB_H
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif // HAVE_NETINET_IN_H
41 #include <netinet/tcp.h>
42 #ifdef HAVE_ARPA_INET_H
43 # include <arpa/inet.h>
44 #endif // HAVE_ARPA_INET_H
47 #endif // HAVE_UNISTD_H
51 #endif // HAVE_SYSLOG_H
54 #endif // HAVE_LIMITS_H
55 #ifdef HAVE_SYS_TIME_H
56 # include <sys/time.h>
57 #endif // HAVE_SYS_TIME_H
58 #include <sys/resource.h>
59 #ifdef HAVE_LIBSYSTEMD
60 # include <systemd/sd-daemon.h>
61 #endif // HAVE_LIBSYSTEMD
69 #include <initializer_list>
72 #include <openssl/ssl.h>
73 #include <openssl/err.h>
74 #include <openssl/rand.h>
77 #include <nghttp2/nghttp2.h>
79 #include "shrpx_config.h"
80 #include "shrpx_tls.h"
81 #include "shrpx_log_config.h"
82 #include "shrpx_worker.h"
83 #include "shrpx_http2_upstream.h"
84 #include "shrpx_http2_session.h"
85 #include "shrpx_worker_process.h"
86 #include "shrpx_process.h"
87 #include "shrpx_signal.h"
88 #include "shrpx_connection.h"
89 #include "shrpx_log.h"
90 #include "shrpx_http.h"
92 #include "app_helper.h"
95 #include "allocator.h"
96 #include "ssl_compat.h"
97 #include "xsi_strerror.h"
99 extern char **environ;
101 using namespace nghttp2;
105 // Deprecated: Environment variables to tell new binary the listening
106 // socket's file descriptors. They are not close-on-exec.
107 constexpr auto ENV_LISTENER4_FD = StringRef::from_lit("NGHTTPX_LISTENER4_FD");
108 constexpr auto ENV_LISTENER6_FD = StringRef::from_lit("NGHTTPX_LISTENER6_FD");
110 // Deprecated: Environment variable to tell new binary the port number
111 // the current binary is listening to.
112 constexpr auto ENV_PORT = StringRef::from_lit("NGHTTPX_PORT");
114 // Deprecated: Environment variable to tell new binary the listening
115 // socket's file descriptor if frontend listens UNIX domain socket.
116 constexpr auto ENV_UNIX_FD = StringRef::from_lit("NGHTTP2_UNIX_FD");
117 // Deprecated: Environment variable to tell new binary the UNIX domain
119 constexpr auto ENV_UNIX_PATH = StringRef::from_lit("NGHTTP2_UNIX_PATH");
121 // Prefix of environment variables to tell new binary the listening
122 // socket's file descriptor. They are not close-on-exec. For TCP
123 // socket, the value must be comma separated 2 parameters: tcp,<FD>.
124 // <FD> is file descriptor. For UNIX domain socket, the value must be
125 // comma separated 3 parameters: unix,<FD>,<PATH>. <FD> is file
126 // descriptor. <PATH> is a path to UNIX domain socket.
127 constexpr auto ENV_ACCEPT_PREFIX = StringRef::from_lit("NGHTTPX_ACCEPT_");
129 // This environment variable contains PID of the original main
130 // process, assuming that it created this main process as a result of
131 // SIGUSR2. The new main process is expected to send QUIT signal to
132 // the original main process to shut it down gracefully.
133 constexpr auto ENV_ORIG_PID = StringRef::from_lit("NGHTTPX_ORIG_PID");
135 // Prefix of environment variables to tell new binary the QUIC IPC
136 // file descriptor and CID prefix of the lingering worker process.
137 // The value must be comma separated parameters:
138 // <FD>,<CID_PREFIX_0>,<CID_PREFIX_1>,... <FD> is the file
139 // descriptor. <CID_PREFIX_I> is the I-th CID prefix in hex encoded
141 constexpr auto ENV_QUIC_WORKER_PROCESS_PREFIX =
142 StringRef::from_lit("NGHTTPX_QUIC_WORKER_PROCESS_");
144 #ifndef _KERNEL_FASTOPEN
145 # define _KERNEL_FASTOPEN
146 // conditional define for TCP_FASTOPEN mostly on ubuntu
147 # ifndef TCP_FASTOPEN
148 # define TCP_FASTOPEN 23
151 // conditional define for SOL_TCP mostly on ubuntu
157 // This configuration is fixed at the first startup of the main
158 // process, and does not change after subsequent reloadings.
159 struct StartupConfig {
160 // This contains all options given in command-line.
161 std::vector<std::pair<StringRef, StringRef>> cmdcfgs;
162 // The current working directory where this process started.
164 // The pointer to original argv (not sure why we have this?)
165 char **original_argv;
166 // The pointer to argv, this is a deep copy of original argv.
168 // The number of elements in argv.
173 StartupConfig suconfig;
176 struct InheritedAddr {
177 // IP address if TCP socket. Otherwise, UNIX domain socket path.
180 // true if UNIX domain socket path
187 void signal_cb(struct ev_loop *loop, ev_signal *w, int revents);
191 void worker_process_child_cb(struct ev_loop *loop, ev_child *w, int revents);
194 struct WorkerProcess {
195 WorkerProcess(struct ev_loop *loop, pid_t worker_pid, int ipc_fd
199 const std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>>
201 #endif // ENABLE_HTTP3
204 worker_pid(worker_pid),
206 termination_deadline(0.)
209 quic_ipc_fd(quic_ipc_fd),
210 cid_prefixes(cid_prefixes)
211 #endif // ENABLE_HTTP3
213 ev_signal_init(&reopen_log_signalev, signal_cb, REOPEN_LOG_SIGNAL);
214 reopen_log_signalev.data = this;
215 ev_signal_start(loop, &reopen_log_signalev);
217 ev_signal_init(&exec_binary_signalev, signal_cb, EXEC_BINARY_SIGNAL);
218 exec_binary_signalev.data = this;
219 ev_signal_start(loop, &exec_binary_signalev);
221 ev_signal_init(&graceful_shutdown_signalev, signal_cb,
222 GRACEFUL_SHUTDOWN_SIGNAL);
223 graceful_shutdown_signalev.data = this;
224 ev_signal_start(loop, &graceful_shutdown_signalev);
226 ev_signal_init(&reload_signalev, signal_cb, RELOAD_SIGNAL);
227 reload_signalev.data = this;
228 ev_signal_start(loop, &reload_signalev);
230 ev_child_init(&worker_process_childev, worker_process_child_cb, worker_pid,
232 worker_process_childev.data = this;
233 ev_child_start(loop, &worker_process_childev);
237 shutdown_signal_watchers();
239 ev_child_stop(loop, &worker_process_childev);
242 if (quic_ipc_fd != -1) {
245 #endif // ENABLE_HTTP3
248 shutdown(ipc_fd, SHUT_WR);
253 void shutdown_signal_watchers() {
254 ev_signal_stop(loop, &reopen_log_signalev);
255 ev_signal_stop(loop, &exec_binary_signalev);
256 ev_signal_stop(loop, &graceful_shutdown_signalev);
257 ev_signal_stop(loop, &reload_signalev);
260 ev_signal reopen_log_signalev;
261 ev_signal exec_binary_signalev;
262 ev_signal graceful_shutdown_signalev;
263 ev_signal reload_signalev;
264 ev_child worker_process_childev;
265 struct ev_loop *loop;
268 ev_tstamp termination_deadline;
271 std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> cid_prefixes;
272 #endif // ENABLE_HTTP3
276 void reload_config(WorkerProcess *wp);
280 std::deque<std::unique_ptr<WorkerProcess>> worker_processes;
284 ev_timer worker_process_grace_period_timer;
288 void worker_process_grace_period_timercb(struct ev_loop *loop, ev_timer *w,
290 auto now = ev_now(loop);
291 ev_tstamp next_repeat = 0.;
293 for (auto it = std::begin(worker_processes);
294 it != std::end(worker_processes);) {
296 if (!(wp->termination_deadline > 0.)) {
302 auto d = wp->termination_deadline - now;
304 if (!(next_repeat > 0.) || d < next_repeat) {
313 LOG(NOTICE) << "Deleting worker process pid=" << wp->worker_pid
314 << " because its grace shutdown period is over";
316 it = worker_processes.erase(it);
319 if (next_repeat > 0.) {
320 w->repeat = next_repeat;
321 ev_timer_again(loop, w);
326 ev_timer_stop(loop, w);
331 void worker_process_set_termination_deadline(WorkerProcess *wp,
332 struct ev_loop *loop) {
333 auto config = get_config();
335 if (!(config->worker_process_grace_shutdown_period > 0.)) {
339 wp->termination_deadline =
340 ev_now(loop) + config->worker_process_grace_shutdown_period;
342 if (!ev_is_active(&worker_process_grace_period_timer)) {
343 worker_process_grace_period_timer.repeat =
344 config->worker_process_grace_shutdown_period;
346 ev_timer_again(loop, &worker_process_grace_period_timer);
352 void worker_process_add(std::unique_ptr<WorkerProcess> wp) {
353 worker_processes.push_back(std::move(wp));
358 void worker_process_remove(const WorkerProcess *wp, struct ev_loop *loop) {
359 for (auto it = std::begin(worker_processes); it != std::end(worker_processes);
367 worker_processes.erase(it);
369 if (worker_processes.empty()) {
370 ev_timer_stop(loop, &worker_process_grace_period_timer);
379 void worker_process_adjust_limit() {
380 auto config = get_config();
382 if (config->max_worker_processes &&
383 worker_processes.size() > config->max_worker_processes) {
384 worker_processes.pop_front();
390 void worker_process_remove_all(struct ev_loop *loop) {
391 std::deque<std::unique_ptr<WorkerProcess>>().swap(worker_processes);
393 ev_timer_stop(loop, &worker_process_grace_period_timer);
398 // Send signal |signum| to all worker processes, and clears
400 void worker_process_kill(int signum, struct ev_loop *loop) {
401 for (auto &s : worker_processes) {
402 if (s->worker_pid == -1) {
405 kill(s->worker_pid, signum);
407 worker_process_remove_all(loop);
412 // Returns the last PID of worker process. Returns -1 if there is no
413 // worker process at the moment.
414 int worker_process_last_pid() {
415 if (worker_processes.empty()) {
419 return worker_processes.back()->worker_pid;
425 std::array<char, STRERROR_BUFSIZE> errbuf;
426 auto config = get_config();
428 constexpr auto SUFFIX = StringRef::from_lit(".XXXXXX");
429 auto &pid_file = config->pid_file;
431 auto len = config->pid_file.size() + SUFFIX.size();
432 auto buf = std::make_unique<char[]>(len + 1);
435 p = std::copy(std::begin(pid_file), std::end(pid_file), p);
436 p = std::copy(std::begin(SUFFIX), std::end(SUFFIX), p);
439 auto temp_path = buf.get();
441 auto fd = mkstemp(temp_path);
444 LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
445 << xsi_strerror(error, errbuf.data(), errbuf.size());
449 auto content = util::utos(config->pid) + '\n';
451 if (write(fd, content.c_str(), content.size()) == -1) {
453 LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
454 << xsi_strerror(error, errbuf.data(), errbuf.size());
458 if (fsync(fd) == -1) {
460 LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
461 << xsi_strerror(error, errbuf.data(), errbuf.size());
467 if (rename(temp_path, pid_file.c_str()) == -1) {
469 LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
470 << xsi_strerror(error, errbuf.data(), errbuf.size());
477 if (config->uid != 0) {
478 if (chown(pid_file.c_str(), config->uid, config->gid) == -1) {
480 LOG(WARN) << "Changing owner of pid file " << pid_file << " failed: "
481 << xsi_strerror(error, errbuf.data(), errbuf.size());
490 void shrpx_sd_notifyf(int unset_environment, const char *format, ...) {
491 #ifdef HAVE_LIBSYSTEMD
494 va_start(args, format);
495 sd_notifyf(unset_environment, format, va_arg(args, char *));
497 #endif // HAVE_LIBSYSTEMD
505 std::array<char, STRERROR_BUFSIZE> errbuf;
507 LOG(NOTICE) << "Executing new binary";
509 shrpx_sd_notifyf(0, "RELOADING=1");
511 rv = shrpx_signal_block_all(&oldset);
514 LOG(ERROR) << "Blocking all signals failed: "
515 << xsi_strerror(error, errbuf.data(), errbuf.size());
525 LOG(ERROR) << "fork() failed errno=" << error;
527 // update PID tracking information in systemd
528 shrpx_sd_notifyf(0, "MAINPID=%d\n", pid);
531 rv = shrpx_signal_set(&oldset);
535 LOG(FATAL) << "Restoring signal mask failed: "
536 << xsi_strerror(error, errbuf.data(), errbuf.size());
546 shrpx_signal_unset_main_proc_ign_handler();
548 rv = shrpx_signal_unblock_all();
551 LOG(ERROR) << "Unblocking all signals failed: "
552 << xsi_strerror(error, errbuf.data(), errbuf.size());
554 nghttp2_Exit(EXIT_FAILURE);
558 util::get_exec_path(suconfig.argc, suconfig.argv, suconfig.cwd);
561 LOG(ERROR) << "Could not resolve the executable path";
562 nghttp2_Exit(EXIT_FAILURE);
565 auto argv = std::make_unique<char *[]>(suconfig.argc + 1);
568 for (int i = 1; i < suconfig.argc; ++i) {
569 argv[i] = suconfig.argv[i];
571 argv[suconfig.argc] = nullptr;
574 for (char **p = environ; *p; ++p, ++envlen)
577 auto config = get_config();
578 auto &listenerconf = config->conn.listener;
580 // 2 for ENV_ORIG_PID and terminal nullptr.
581 auto envp = std::make_unique<char *[]>(envlen + listenerconf.addrs.size() +
582 worker_processes.size() + 2);
585 std::vector<ImmutableString> fd_envs;
586 for (size_t i = 0; i < listenerconf.addrs.size(); ++i) {
587 auto &addr = listenerconf.addrs[i];
588 auto s = ENV_ACCEPT_PREFIX.str();
589 s += util::utos(i + 1);
591 if (addr.host_unix) {
593 s += util::utos(addr.fd);
598 s += util::utos(addr.fd);
601 fd_envs.emplace_back(s);
602 envp[envidx++] = const_cast<char *>(fd_envs.back().c_str());
605 auto ipc_fd_str = ENV_ORIG_PID.str();
607 ipc_fd_str += util::utos(config->pid);
608 envp[envidx++] = const_cast<char *>(ipc_fd_str.c_str());
611 std::vector<ImmutableString> quic_lwps;
612 for (size_t i = 0; i < worker_processes.size(); ++i) {
613 auto &wp = worker_processes[i];
614 auto s = ENV_QUIC_WORKER_PROCESS_PREFIX.str();
615 s += util::utos(i + 1);
617 s += util::utos(wp->quic_ipc_fd);
618 for (auto &cid_prefix : wp->cid_prefixes) {
620 s += util::format_hex(cid_prefix);
623 quic_lwps.emplace_back(s);
624 envp[envidx++] = const_cast<char *>(quic_lwps.back().c_str());
626 #endif // ENABLE_HTTP3
628 for (size_t i = 0; i < envlen; ++i) {
629 auto env = StringRef{environ[i]};
630 if (util::starts_with(env, ENV_ACCEPT_PREFIX) ||
631 util::starts_with(env, ENV_LISTENER4_FD) ||
632 util::starts_with(env, ENV_LISTENER6_FD) ||
633 util::starts_with(env, ENV_PORT) ||
634 util::starts_with(env, ENV_UNIX_FD) ||
635 util::starts_with(env, ENV_UNIX_PATH) ||
636 util::starts_with(env, ENV_ORIG_PID) ||
637 util::starts_with(env, ENV_QUIC_WORKER_PROCESS_PREFIX)) {
641 envp[envidx++] = environ[i];
644 envp[envidx++] = nullptr;
646 if (LOG_ENABLED(INFO)) {
647 LOG(INFO) << "cmdline";
648 for (int i = 0; argv[i]; ++i) {
649 LOG(INFO) << i << ": " << argv[i];
651 LOG(INFO) << "environ";
652 for (int i = 0; envp[i]; ++i) {
653 LOG(INFO) << i << ": " << envp[i];
657 // restores original stderr
658 restore_original_fds();
660 // reloading finished
661 shrpx_sd_notifyf(0, "READY=1");
663 if (execve(argv[0], argv.get(), envp.get()) == -1) {
665 LOG(ERROR) << "execve failed: errno=" << error;
666 nghttp2_Exit(EXIT_FAILURE);
672 void ipc_send(WorkerProcess *wp, uint8_t ipc_event) {
673 std::array<char, STRERROR_BUFSIZE> errbuf;
675 while ((nwrite = write(wp->ipc_fd, &ipc_event, 1)) == -1 && errno == EINTR)
680 LOG(ERROR) << "Could not send IPC event to worker process: "
681 << xsi_strerror(error, errbuf.data(), errbuf.size());
686 LOG(ERROR) << "Could not send IPC event due to pipe overflow";
693 void reopen_log(WorkerProcess *wp) {
694 LOG(NOTICE) << "Reopening log files: main process";
696 auto config = get_config();
697 auto &loggingconf = config->logging;
699 (void)reopen_log_files(loggingconf);
700 redirect_stderr_to_errorlog(loggingconf);
701 ipc_send(wp, SHRPX_IPC_REOPEN_LOG);
706 void signal_cb(struct ev_loop *loop, ev_signal *w, int revents) {
707 auto wp = static_cast<WorkerProcess *>(w->data);
708 if (wp->worker_pid == -1) {
714 case REOPEN_LOG_SIGNAL:
717 case EXEC_BINARY_SIGNAL:
720 case GRACEFUL_SHUTDOWN_SIGNAL: {
721 auto &listenerconf = get_config()->conn.listener;
722 for (auto &addr : listenerconf.addrs) {
725 ipc_send(wp, SHRPX_IPC_GRACEFUL_SHUTDOWN);
726 worker_process_set_termination_deadline(wp, loop);
733 worker_process_kill(w->signum, loop);
741 void worker_process_child_cb(struct ev_loop *loop, ev_child *w, int revents) {
742 auto wp = static_cast<WorkerProcess *>(w->data);
744 log_chld(w->rpid, w->rstatus, "Worker process");
746 auto pid = wp->worker_pid;
748 worker_process_remove(wp, loop);
750 if (worker_process_last_pid() == pid) {
757 int create_unix_domain_server_socket(UpstreamAddr &faddr,
758 std::vector<InheritedAddr> &iaddrs) {
759 std::array<char, STRERROR_BUFSIZE> errbuf;
760 auto found = std::find_if(
761 std::begin(iaddrs), std::end(iaddrs), [&faddr](const InheritedAddr &ia) {
762 return !ia.used && ia.host_unix && ia.host == faddr.host;
765 if (found != std::end(iaddrs)) {
766 LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host
767 << (faddr.tls ? ", tls" : "");
768 (*found).used = true;
769 faddr.fd = (*found).fd;
770 faddr.hostport = StringRef::from_lit("localhost");
776 auto fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
779 LOG(FATAL) << "socket() syscall failed: "
780 << xsi_strerror(error, errbuf.data(), errbuf.size());
783 #else // !SOCK_NONBLOCK
784 auto fd = socket(AF_UNIX, SOCK_STREAM, 0);
787 LOG(FATAL) << "socket() syscall failed: "
788 << xsi_strerror(error, errbuf.data(), errbuf.size());
791 util::make_socket_nonblocking(fd);
792 #endif // !SOCK_NONBLOCK
794 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
795 static_cast<socklen_t>(sizeof(val))) == -1) {
797 LOG(FATAL) << "Failed to set SO_REUSEADDR option to listener socket: "
798 << xsi_strerror(error, errbuf.data(), errbuf.size());
804 addr.un.sun_family = AF_UNIX;
805 if (faddr.host.size() + 1 > sizeof(addr.un.sun_path)) {
806 LOG(FATAL) << "UNIX domain socket path " << faddr.host << " is too long > "
807 << sizeof(addr.un.sun_path);
811 // copy path including terminal NULL
812 std::copy_n(faddr.host.c_str(), faddr.host.size() + 1, addr.un.sun_path);
814 // unlink (remove) already existing UNIX domain socket path
815 unlink(faddr.host.c_str());
817 if (bind(fd, &addr.sa, sizeof(addr.un)) != 0) {
819 LOG(FATAL) << "Failed to bind UNIX domain socket: "
820 << xsi_strerror(error, errbuf.data(), errbuf.size());
825 auto &listenerconf = get_config()->conn.listener;
827 if (listen(fd, listenerconf.backlog) != 0) {
829 LOG(FATAL) << "Failed to listen to UNIX domain socket: "
830 << xsi_strerror(error, errbuf.data(), errbuf.size());
835 LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host
836 << (faddr.tls ? ", tls" : "");
839 faddr.hostport = StringRef::from_lit("localhost");
846 int create_tcp_server_socket(UpstreamAddr &faddr,
847 std::vector<InheritedAddr> &iaddrs) {
848 std::array<char, STRERROR_BUFSIZE> errbuf;
852 auto &listenerconf = get_config()->conn.listener;
854 auto service = util::utos(faddr.port);
856 hints.ai_family = faddr.family;
857 hints.ai_socktype = SOCK_STREAM;
858 hints.ai_flags = AI_PASSIVE;
860 hints.ai_flags |= AI_ADDRCONFIG;
861 #endif // AI_ADDRCONFIG
864 faddr.host == StringRef::from_lit("*") ? nullptr : faddr.host.c_str();
867 rv = getaddrinfo(node, service.c_str(), &hints, &res);
870 // Retry without AI_ADDRCONFIG
871 hints.ai_flags &= ~AI_ADDRCONFIG;
872 rv = getaddrinfo(node, service.c_str(), &hints, &res);
874 #endif // AI_ADDRCONFIG
876 LOG(FATAL) << "Unable to get IPv" << (faddr.family == AF_INET ? "4" : "6")
877 << " address for " << faddr.host << ", port " << faddr.port
878 << ": " << gai_strerror(rv);
882 auto res_d = defer(freeaddrinfo, res);
884 std::array<char, NI_MAXHOST> host;
886 for (rp = res; rp; rp = rp->ai_next) {
888 rv = getnameinfo(rp->ai_addr, rp->ai_addrlen, host.data(), host.size(),
889 nullptr, 0, NI_NUMERICHOST);
892 LOG(WARN) << "getnameinfo() failed: " << gai_strerror(rv);
896 auto found = std::find_if(std::begin(iaddrs), std::end(iaddrs),
897 [&host, &faddr](const InheritedAddr &ia) {
898 return !ia.used && !ia.host_unix &&
899 ia.host == host.data() &&
900 ia.port == faddr.port;
903 if (found != std::end(iaddrs)) {
904 (*found).used = true;
911 socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK, rp->ai_protocol);
914 LOG(WARN) << "socket() syscall failed: "
915 << xsi_strerror(error, errbuf.data(), errbuf.size());
918 #else // !SOCK_NONBLOCK
919 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
922 LOG(WARN) << "socket() syscall failed: "
923 << xsi_strerror(error, errbuf.data(), errbuf.size());
926 util::make_socket_nonblocking(fd);
927 #endif // !SOCK_NONBLOCK
929 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
930 static_cast<socklen_t>(sizeof(val))) == -1) {
932 LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: "
933 << xsi_strerror(error, errbuf.data(), errbuf.size());
939 if (faddr.family == AF_INET6) {
940 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
941 static_cast<socklen_t>(sizeof(val))) == -1) {
943 LOG(WARN) << "Failed to set IPV6_V6ONLY option to listener socket: "
944 << xsi_strerror(error, errbuf.data(), errbuf.size());
949 #endif // IPV6_V6ONLY
951 #ifdef TCP_DEFER_ACCEPT
953 if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val,
954 static_cast<socklen_t>(sizeof(val))) == -1) {
956 LOG(WARN) << "Failed to set TCP_DEFER_ACCEPT option to listener socket: "
957 << xsi_strerror(error, errbuf.data(), errbuf.size());
959 #endif // TCP_DEFER_ACCEPT
961 // When we are executing new binary, and the old binary did not
962 // bind privileged port (< 1024) for some reason, binding to those
963 // ports will fail with permission denied error.
964 if (bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
966 LOG(WARN) << "bind() syscall failed: "
967 << xsi_strerror(error, errbuf.data(), errbuf.size());
972 if (listenerconf.fastopen > 0) {
973 val = listenerconf.fastopen;
974 if (setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &val,
975 static_cast<socklen_t>(sizeof(val))) == -1) {
977 LOG(WARN) << "Failed to set TCP_FASTOPEN option to listener socket: "
978 << xsi_strerror(error, errbuf.data(), errbuf.size());
982 if (listen(fd, listenerconf.backlog) == -1) {
984 LOG(WARN) << "listen() syscall failed: "
985 << xsi_strerror(error, errbuf.data(), errbuf.size());
994 LOG(FATAL) << "Listening " << (faddr.family == AF_INET ? "IPv4" : "IPv6")
1001 faddr.hostport = util::make_http_hostport(mod_config()->balloc,
1002 StringRef{host.data()}, faddr.port);
1004 LOG(NOTICE) << "Listening on " << faddr.hostport
1005 << (faddr.tls ? ", tls" : "");
1012 // Returns array of InheritedAddr constructed from |config|. This
1013 // function is intended to be used when reloading configuration, and
1014 // |config| is usually a current configuration.
1015 std::vector<InheritedAddr>
1016 get_inherited_addr_from_config(BlockAllocator &balloc, Config *config) {
1017 std::array<char, STRERROR_BUFSIZE> errbuf;
1020 auto &listenerconf = config->conn.listener;
1022 std::vector<InheritedAddr> iaddrs(listenerconf.addrs.size());
1025 for (auto &addr : listenerconf.addrs) {
1026 auto &iaddr = iaddrs[idx++];
1028 if (addr.host_unix) {
1029 iaddr.host = addr.host;
1030 iaddr.host_unix = true;
1036 iaddr.port = addr.port;
1039 // We have to getsockname/getnameinfo for fd, since we may have
1040 // '*' appear in addr.host, which makes comparison against "real"
1044 socklen_t salen = sizeof(su);
1046 // We already added entry to iaddrs. Even if we got errors, we
1047 // don't remove it. This is required because we have to close the
1048 // socket if it is not reused. The empty host name usually does
1049 // not match anything.
1051 if (getsockname(addr.fd, &su.sa, &salen) != 0) {
1053 LOG(WARN) << "getsockname() syscall failed (fd=" << addr.fd
1054 << "): " << xsi_strerror(error, errbuf.data(), errbuf.size());
1058 std::array<char, NI_MAXHOST> host;
1059 rv = getnameinfo(&su.sa, salen, host.data(), host.size(), nullptr, 0,
1062 LOG(WARN) << "getnameinfo() failed (fd=" << addr.fd
1063 << "): " << gai_strerror(rv);
1067 iaddr.host = make_string_ref(balloc, StringRef{host.data()});
1075 // Returns array of InheritedAddr constructed from environment
1076 // variables. This function handles the old environment variable
1077 // names used in 1.7.0 or earlier.
1078 std::vector<InheritedAddr> get_inherited_addr_from_env(Config *config) {
1079 std::array<char, STRERROR_BUFSIZE> errbuf;
1081 std::vector<InheritedAddr> iaddrs;
1084 // Upgrade from 1.7.0 or earlier
1085 auto portenv = getenv(ENV_PORT.c_str());
1088 for (auto env_name : {ENV_LISTENER4_FD, ENV_LISTENER6_FD}) {
1089 auto fdenv = getenv(env_name.c_str());
1091 auto name = ENV_ACCEPT_PREFIX.str();
1092 name += util::utos(i);
1093 std::string value = "tcp,";
1095 setenv(name.c_str(), value.c_str(), 0);
1100 // The return value of getenv may be allocated statically.
1101 if (getenv(ENV_UNIX_PATH.c_str()) && getenv(ENV_UNIX_FD.c_str())) {
1102 auto name = ENV_ACCEPT_PREFIX.str();
1104 std::string value = "unix,";
1105 value += getenv(ENV_UNIX_FD.c_str());
1107 value += getenv(ENV_UNIX_PATH.c_str());
1108 setenv(name.c_str(), value.c_str(), 0);
1113 for (size_t i = 1;; ++i) {
1114 auto name = ENV_ACCEPT_PREFIX.str();
1115 name += util::utos(i);
1116 auto env = getenv(name.c_str());
1121 if (LOG_ENABLED(INFO)) {
1122 LOG(INFO) << "Read env " << name << "=" << env;
1125 auto end_type = strchr(env, ',');
1130 auto type = StringRef(env, end_type);
1131 auto value = end_type + 1;
1133 if (type == StringRef::from_lit("unix")) {
1134 auto endfd = strchr(value, ',');
1138 auto fd = util::parse_uint(reinterpret_cast<const uint8_t *>(value),
1141 LOG(WARN) << "Could not parse file descriptor from "
1142 << std::string(value, endfd - value);
1146 auto path = endfd + 1;
1147 if (strlen(path) == 0) {
1148 LOG(WARN) << "Empty UNIX domain socket path (fd=" << fd << ")";
1153 if (LOG_ENABLED(INFO)) {
1154 LOG(INFO) << "Inherit UNIX domain socket fd=" << fd
1155 << ", path=" << path;
1158 InheritedAddr addr{};
1159 addr.host = make_string_ref(config->balloc, StringRef{path});
1160 addr.host_unix = true;
1161 addr.fd = static_cast<int>(fd);
1162 iaddrs.push_back(std::move(addr));
1165 if (type == StringRef::from_lit("tcp")) {
1166 auto fd = util::parse_uint(value);
1168 LOG(WARN) << "Could not parse file descriptor from " << value;
1173 socklen_t salen = sizeof(su);
1175 if (getsockname(fd, &su.sa, &salen) != 0) {
1177 LOG(WARN) << "getsockname() syscall failed (fd=" << fd
1178 << "): " << xsi_strerror(error, errbuf.data(), errbuf.size());
1185 switch (su.storage.ss_family) {
1187 port = ntohs(su.in.sin_port);
1190 port = ntohs(su.in6.sin6_port);
1197 std::array<char, NI_MAXHOST> host;
1198 rv = getnameinfo(&su.sa, salen, host.data(), host.size(), nullptr, 0,
1201 LOG(WARN) << "getnameinfo() failed (fd=" << fd
1202 << "): " << gai_strerror(rv);
1207 if (LOG_ENABLED(INFO)) {
1208 LOG(INFO) << "Inherit TCP socket fd=" << fd
1209 << ", address=" << host.data() << ", port=" << port;
1212 InheritedAddr addr{};
1213 addr.host = make_string_ref(config->balloc, StringRef{host.data()});
1214 addr.port = static_cast<uint16_t>(port);
1215 addr.fd = static_cast<int>(fd);
1216 iaddrs.push_back(std::move(addr));
1226 // Closes all sockets which are not reused.
1227 void close_unused_inherited_addr(const std::vector<InheritedAddr> &iaddrs) {
1228 for (auto &ia : iaddrs) {
1239 // Returns the PID of the original main process from environment
1240 // variable ENV_ORIG_PID.
1241 pid_t get_orig_pid_from_env() {
1242 auto s = getenv(ENV_ORIG_PID.c_str());
1246 return util::parse_uint(s);
1252 std::vector<QUICLingeringWorkerProcess>
1253 inherited_quic_lingering_worker_processes;
1257 std::vector<QUICLingeringWorkerProcess>
1258 get_inherited_quic_lingering_worker_process_from_env() {
1259 std::vector<QUICLingeringWorkerProcess> iwps;
1261 for (size_t i = 1;; ++i) {
1262 auto name = ENV_QUIC_WORKER_PROCESS_PREFIX.str();
1263 name += util::utos(i);
1264 auto env = getenv(name.c_str());
1269 if (LOG_ENABLED(INFO)) {
1270 LOG(INFO) << "Read env " << name << "=" << env;
1273 auto envend = env + strlen(env);
1275 auto end_fd = std::find(env, envend, ',');
1276 if (end_fd == envend) {
1281 util::parse_uint(reinterpret_cast<const uint8_t *>(env), end_fd - env);
1283 LOG(WARN) << "Could not parse file descriptor from "
1284 << StringRef{env, static_cast<size_t>(end_fd - env)};
1288 if (LOG_ENABLED(INFO)) {
1289 LOG(INFO) << "Inherit worker process QUIC IPC socket fd=" << fd;
1292 util::make_socket_closeonexec(fd);
1294 std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> cid_prefixes;
1296 auto p = end_fd + 1;
1298 auto end = std::find(p, envend, ',');
1300 auto hex_cid_prefix = StringRef{p, end};
1301 if (hex_cid_prefix.size() != SHRPX_QUIC_CID_PREFIXLEN * 2 ||
1302 !util::is_hex_string(hex_cid_prefix)) {
1303 LOG(WARN) << "Found invalid CID prefix=" << hex_cid_prefix;
1307 if (LOG_ENABLED(INFO)) {
1308 LOG(INFO) << "Inherit worker process CID prefix=" << hex_cid_prefix;
1311 cid_prefixes.emplace_back();
1313 util::decode_hex(std::begin(cid_prefixes.back()), hex_cid_prefix);
1315 if (end == envend) {
1322 iwps.emplace_back(std::move(cid_prefixes), fd);
1328 #endif // ENABLE_HTTP3
1331 int create_acceptor_socket(Config *config, std::vector<InheritedAddr> &iaddrs) {
1332 std::array<char, STRERROR_BUFSIZE> errbuf;
1333 auto &listenerconf = config->conn.listener;
1335 for (auto &addr : listenerconf.addrs) {
1336 if (addr.host_unix) {
1337 if (create_unix_domain_server_socket(addr, iaddrs) != 0) {
1341 if (config->uid != 0) {
1342 // fd is not associated to inode, so we cannot use fchown(2)
1343 // here. https://lkml.org/lkml/2004/11/1/84
1344 if (chown(addr.host.c_str(), config->uid, config->gid) == -1) {
1346 LOG(WARN) << "Changing owner of UNIX domain socket " << addr.host
1348 << xsi_strerror(error, errbuf.data(), errbuf.size());
1354 if (create_tcp_server_socket(addr, iaddrs) != 0) {
1366 return _daemonize(0, 0, 0, 0);
1368 # ifdef HAVE_LIBSYSTEMD
1369 if (sd_booted() && (getenv("NOTIFY_SOCKET") != nullptr)) {
1370 LOG(NOTICE) << "Daemonising disabled under systemd";
1374 # endif // HAVE_LIBSYSTEMD
1375 return util::daemonize(0, 0);
1381 // Opens IPC socket used to communicate with worker proess. The
1382 // communication is unidirectional; that is main process sends
1383 // messages to the worker process. On success, ipc_fd[0] is for
1384 // reading, and ipc_fd[1] for writing, just like pipe(2).
1385 int create_ipc_socket(std::array<int, 2> &ipc_fd) {
1386 std::array<char, STRERROR_BUFSIZE> errbuf;
1389 rv = pipe(ipc_fd.data());
1392 LOG(WARN) << "Failed to create pipe to communicate worker process: "
1393 << xsi_strerror(error, errbuf.data(), errbuf.size());
1397 for (int i = 0; i < 2; ++i) {
1398 auto fd = ipc_fd[i];
1399 util::make_socket_nonblocking(fd);
1400 util::make_socket_closeonexec(fd);
1409 int create_quic_ipc_socket(std::array<int, 2> &quic_ipc_fd) {
1410 std::array<char, STRERROR_BUFSIZE> errbuf;
1413 rv = socketpair(AF_UNIX, SOCK_DGRAM, 0, quic_ipc_fd.data());
1416 LOG(WARN) << "Failed to create socket pair to communicate worker process: "
1417 << xsi_strerror(error, errbuf.data(), errbuf.size());
1421 for (auto fd : quic_ipc_fd) {
1422 util::make_socket_nonblocking(fd);
1430 int generate_cid_prefix(
1431 std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> &cid_prefixes,
1432 const Config *config) {
1433 auto &apiconf = config->api;
1434 auto &quicconf = config->quic;
1436 size_t num_cid_prefix;
1437 if (config->single_thread) {
1440 num_cid_prefix = config->num_worker;
1442 // API endpoint occupies the one dedicated worker thread.
1443 // Although such worker never gets QUIC traffic, we create CID
1444 // prefix for it to make code a bit simpler.
1445 if (apiconf.enabled) {
1450 cid_prefixes.resize(num_cid_prefix);
1452 for (auto &cid_prefix : cid_prefixes) {
1453 if (create_cid_prefix(cid_prefix.data(), quicconf.server_id.data()) != 0) {
1463 std::vector<QUICLingeringWorkerProcess>
1464 collect_quic_lingering_worker_processes() {
1465 std::vector<QUICLingeringWorkerProcess> quic_lwps{
1466 std::begin(inherited_quic_lingering_worker_processes),
1467 std::end(inherited_quic_lingering_worker_processes)};
1469 for (auto &wp : worker_processes) {
1470 quic_lwps.emplace_back(wp->cid_prefixes, wp->quic_ipc_fd);
1476 #endif // ENABLE_HTTP3
1479 // Creates worker process, and returns PID of worker process. On
1480 // success, file descriptor for IPC (send only) is assigned to
1481 // |main_ipc_fd|. In child process, we will close file descriptors
1482 // which are inherited from previous configuration/process, but not
1483 // used in the current configuration.
1484 pid_t fork_worker_process(
1489 #endif // ENABLE_HTTP3
1491 const std::vector<InheritedAddr> &iaddrs
1494 const std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>>
1496 const std::vector<QUICLingeringWorkerProcess> &quic_lwps
1497 #endif // ENABLE_HTTP3
1499 std::array<char, STRERROR_BUFSIZE> errbuf;
1503 std::array<int, 2> ipc_fd;
1505 rv = create_ipc_socket(ipc_fd);
1511 std::array<int, 2> quic_ipc_fd;
1513 rv = create_quic_ipc_socket(quic_ipc_fd);
1517 #endif // ENABLE_HTTP3
1519 rv = shrpx_signal_block_all(&oldset);
1522 LOG(ERROR) << "Blocking all signals failed: "
1523 << xsi_strerror(error, errbuf.data(), errbuf.size());
1531 auto config = get_config();
1535 if (!config->single_process) {
1540 ev_loop_fork(EV_DEFAULT);
1542 for (auto &addr : config->conn.listener.addrs) {
1543 util::make_socket_closeonexec(addr.fd);
1547 util::make_socket_closeonexec(quic_ipc_fd[0]);
1549 for (auto &lwp : quic_lwps) {
1550 util::make_socket_closeonexec(lwp.quic_ipc_fd);
1553 for (auto &wp : worker_processes) {
1554 util::make_socket_closeonexec(wp->quic_ipc_fd);
1555 // Do not close quic_ipc_fd.
1556 wp->quic_ipc_fd = -1;
1558 #endif // ENABLE_HTTP3
1560 // Remove all WorkerProcesses to stop any registered watcher on
1562 worker_process_remove_all(EV_DEFAULT);
1564 close_unused_inherited_addr(iaddrs);
1566 shrpx_signal_set_worker_proc_ign_handler();
1568 rv = shrpx_signal_unblock_all();
1571 LOG(FATAL) << "Unblocking all signals failed: "
1572 << xsi_strerror(error, errbuf.data(), errbuf.size());
1574 if (config->single_process) {
1577 nghttp2_Exit(EXIT_FAILURE);
1581 if (!config->single_process) {
1584 close(quic_ipc_fd[1]);
1585 #endif // ENABLE_HTTP3
1588 WorkerProcessConfig wpconf{
1589 .ipc_fd = ipc_fd[0],
1591 .cid_prefixes = cid_prefixes,
1592 .quic_ipc_fd = quic_ipc_fd[0],
1593 .quic_lingering_worker_processes = quic_lwps,
1594 #endif // ENABLE_HTTP3
1596 rv = worker_process_event_loop(&wpconf);
1598 LOG(FATAL) << "Worker process returned error";
1600 if (config->single_process) {
1603 nghttp2_Exit(EXIT_FAILURE);
1607 LOG(NOTICE) << "Worker process shutting down momentarily";
1609 // call exit(...) instead of nghttp2_Exit to get leak sanitizer report
1610 if (config->single_process) {
1613 nghttp2_Exit(EXIT_SUCCESS);
1620 LOG(ERROR) << "Could not spawn worker process: "
1621 << xsi_strerror(error, errbuf.data(), errbuf.size());
1624 rv = shrpx_signal_set(&oldset);
1627 LOG(FATAL) << "Restoring signal mask failed: "
1628 << xsi_strerror(error, errbuf.data(), errbuf.size());
1637 close(quic_ipc_fd[0]);
1638 close(quic_ipc_fd[1]);
1639 #endif // ENABLE_HTTP3
1646 close(quic_ipc_fd[0]);
1647 #endif // ENABLE_HTTP3
1649 main_ipc_fd = ipc_fd[1];
1651 wp_quic_ipc_fd = quic_ipc_fd[1];
1652 #endif // ENABLE_HTTP3
1654 LOG(NOTICE) << "Worker process [" << pid << "] spawned";
1662 std::array<char, STRERROR_BUFSIZE> errbuf;
1664 shrpx_signal_set_main_proc_ign_handler();
1666 auto config = mod_config();
1668 if (config->daemon) {
1669 if (call_daemon() == -1) {
1671 LOG(FATAL) << "Failed to daemonize: "
1672 << xsi_strerror(error, errbuf.data(), errbuf.size());
1676 // We get new PID after successful daemon().
1677 mod_config()->pid = getpid();
1679 // daemon redirects stderr file descriptor to /dev/null, so we
1681 redirect_stderr_to_errorlog(config->logging);
1684 // update systemd PID tracking
1685 shrpx_sd_notifyf(0, "MAINPID=%d\n", config->pid);
1688 auto iaddrs = get_inherited_addr_from_env(config);
1690 if (create_acceptor_socket(config, iaddrs) != 0) {
1694 close_unused_inherited_addr(iaddrs);
1697 auto orig_pid = get_orig_pid_from_env();
1700 inherited_quic_lingering_worker_processes =
1701 get_inherited_quic_lingering_worker_process_from_env();
1702 #endif // ENABLE_HTTP3
1704 auto loop = ev_default_loop(config->ev_loop_flags);
1708 int quic_ipc_fd = 0;
1710 auto quic_lwps = collect_quic_lingering_worker_processes();
1712 std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> cid_prefixes;
1714 if (generate_cid_prefix(cid_prefixes, config) != 0) {
1717 #endif // ENABLE_HTTP3
1719 auto pid = fork_worker_process(
1724 #endif // ENABLE_HTTP3
1729 cid_prefixes, quic_lwps
1730 #endif // ENABLE_HTTP3
1737 ev_timer_init(&worker_process_grace_period_timer,
1738 worker_process_grace_period_timercb, 0., 0.);
1740 worker_process_add(std::make_unique<WorkerProcess>(loop, pid, ipc_fd
1743 quic_ipc_fd, cid_prefixes
1744 #endif // ENABLE_HTTP3
1747 // Write PID file when we are ready to accept connection from peer.
1748 // This makes easier to write restart script for nghttpx. Because
1749 // when we know that PID file is recreated, it means we can send
1750 // QUIT signal to the old process to make it shutdown gracefully.
1751 if (!config->pid_file.empty()) {
1755 // ready to serve requests
1756 shrpx_sd_notifyf(0, "READY=1");
1758 if (orig_pid != -1) {
1759 LOG(NOTICE) << "Send QUIT signal to the original main process to tell "
1760 "that we are ready to serve requests.";
1761 kill(orig_pid, SIGQUIT);
1766 ev_timer_stop(loop, &worker_process_grace_period_timer);
1773 // Returns true if regular file or symbolic link |path| exists.
1774 bool conf_exists(const char *path) {
1776 int rv = stat(path, &buf);
1777 return rv == 0 && (buf.st_mode & (S_IFREG | S_IFLNK));
1782 constexpr auto DEFAULT_NPN_LIST =
1783 StringRef::from_lit("h2,h2-16,h2-14,http/1.1");
1787 constexpr auto DEFAULT_TLS_MIN_PROTO_VERSION = StringRef::from_lit("TLSv1.2");
1788 #ifdef TLS1_3_VERSION
1789 constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.3");
1790 #else // !TLS1_3_VERSION
1791 constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.2");
1792 #endif // !TLS1_3_VERSION
1796 constexpr auto DEFAULT_ACCESSLOG_FORMAT =
1797 StringRef::from_lit(R"($remote_addr - - [$time_local] )"
1798 R"("$request" $status $body_bytes_sent )"
1799 R"("$http_referer" "$http_user_agent")");
1803 void fill_default_config(Config *config) {
1804 config->num_worker = 1;
1805 config->conf_path = StringRef::from_lit("/etc/nghttpx/nghttpx.conf");
1806 config->pid = getpid();
1809 config->single_thread = true;
1812 if (ev_supported_backends() & ~ev_recommended_backends() & EVBACKEND_KQUEUE) {
1813 config->ev_loop_flags = ev_recommended_backends() | EVBACKEND_KQUEUE;
1816 auto &tlsconf = config->tls;
1818 auto &ticketconf = tlsconf.ticket;
1820 auto &memcachedconf = ticketconf.memcached;
1821 memcachedconf.max_retry = 3;
1822 memcachedconf.max_fail = 2;
1823 memcachedconf.interval = 10_min;
1824 memcachedconf.family = AF_UNSPEC;
1827 auto &session_cacheconf = tlsconf.session_cache;
1829 auto &memcachedconf = session_cacheconf.memcached;
1830 memcachedconf.family = AF_UNSPEC;
1833 ticketconf.cipher = EVP_aes_128_cbc();
1837 auto &ocspconf = tlsconf.ocsp;
1838 // ocsp update interval = 14400 secs = 4 hours, borrowed from h2o
1839 ocspconf.update_interval = 4_h;
1840 ocspconf.fetch_ocsp_response_file =
1841 StringRef::from_lit(PKGDATADIR "/fetch-ocsp-response");
1845 auto &dyn_recconf = tlsconf.dyn_rec;
1846 dyn_recconf.warmup_threshold = 1_m;
1847 dyn_recconf.idle_timeout = 1_s;
1850 tlsconf.session_timeout = std::chrono::hours(12);
1851 tlsconf.ciphers = StringRef::from_lit(nghttp2::tls::DEFAULT_CIPHER_LIST);
1852 tlsconf.tls13_ciphers =
1853 StringRef::from_lit(nghttp2::tls::DEFAULT_TLS13_CIPHER_LIST);
1854 tlsconf.client.ciphers =
1855 StringRef::from_lit(nghttp2::tls::DEFAULT_CIPHER_LIST);
1856 tlsconf.client.tls13_ciphers =
1857 StringRef::from_lit(nghttp2::tls::DEFAULT_TLS13_CIPHER_LIST);
1858 tlsconf.min_proto_version =
1859 tls::proto_version_from_string(DEFAULT_TLS_MIN_PROTO_VERSION);
1860 tlsconf.max_proto_version =
1861 tls::proto_version_from_string(DEFAULT_TLS_MAX_PROTO_VERSION);
1862 tlsconf.max_early_data = 16_k;
1863 #if OPENSSL_1_1_API || defined(OPENSSL_IS_BORINGSSL)
1864 tlsconf.ecdh_curves = StringRef::from_lit("X25519:P-256:P-384:P-521");
1865 #else // !OPENSSL_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
1866 tlsconf.ecdh_curves = StringRef::from_lit("P-256:P-384:P-521");
1867 #endif // !OPENSSL_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
1869 auto &httpconf = config->http;
1870 httpconf.server_name = StringRef::from_lit("nghttpx");
1871 httpconf.no_host_rewrite = true;
1872 httpconf.request_header_field_buffer = 64_k;
1873 httpconf.max_request_header_fields = 100;
1874 httpconf.response_header_field_buffer = 64_k;
1875 httpconf.max_response_header_fields = 500;
1876 httpconf.redirect_https_port = StringRef::from_lit("443");
1877 httpconf.max_requests = std::numeric_limits<size_t>::max();
1878 httpconf.xfp.add = true;
1879 httpconf.xfp.strip_incoming = true;
1880 httpconf.early_data.strip_incoming = true;
1882 auto &http2conf = config->http2;
1884 auto &upstreamconf = http2conf.upstream;
1887 auto &timeoutconf = upstreamconf.timeout;
1888 timeoutconf.settings = 10_s;
1891 // window size for HTTP/2 upstream connection per stream. 2**16-1
1892 // = 64KiB-1, which is HTTP/2 default.
1893 upstreamconf.window_size = 64_k - 1;
1894 // HTTP/2 has connection-level flow control. The default window
1895 // size for HTTP/2 is 64KiB - 1.
1896 upstreamconf.connection_window_size = 64_k - 1;
1897 upstreamconf.max_concurrent_streams = 100;
1899 upstreamconf.encoder_dynamic_table_size = 4_k;
1900 upstreamconf.decoder_dynamic_table_size = 4_k;
1902 nghttp2_option_new(&upstreamconf.option);
1903 nghttp2_option_set_no_auto_window_update(upstreamconf.option, 1);
1904 nghttp2_option_set_no_recv_client_magic(upstreamconf.option, 1);
1905 nghttp2_option_set_max_deflate_dynamic_table_size(
1906 upstreamconf.option, upstreamconf.encoder_dynamic_table_size);
1908 // For API endpoint, we enable automatic window update. This is
1909 // because we are a sink.
1910 nghttp2_option_new(&upstreamconf.alt_mode_option);
1911 nghttp2_option_set_no_recv_client_magic(upstreamconf.alt_mode_option, 1);
1912 nghttp2_option_set_max_deflate_dynamic_table_size(
1913 upstreamconf.alt_mode_option, upstreamconf.encoder_dynamic_table_size);
1916 http2conf.timeout.stream_write = 1_min;
1919 auto &downstreamconf = http2conf.downstream;
1922 auto &timeoutconf = downstreamconf.timeout;
1923 timeoutconf.settings = 10_s;
1926 downstreamconf.window_size = 64_k - 1;
1927 downstreamconf.connection_window_size = (1u << 31) - 1;
1928 downstreamconf.max_concurrent_streams = 100;
1930 downstreamconf.encoder_dynamic_table_size = 4_k;
1931 downstreamconf.decoder_dynamic_table_size = 4_k;
1933 nghttp2_option_new(&downstreamconf.option);
1934 nghttp2_option_set_no_auto_window_update(downstreamconf.option, 1);
1935 nghttp2_option_set_peer_max_concurrent_streams(downstreamconf.option, 100);
1936 nghttp2_option_set_max_deflate_dynamic_table_size(
1937 downstreamconf.option, downstreamconf.encoder_dynamic_table_size);
1941 auto &quicconf = config->quic;
1943 auto &upstreamconf = quicconf.upstream;
1946 auto &timeoutconf = upstreamconf.timeout;
1947 timeoutconf.idle = 30_s;
1950 auto &bpfconf = quicconf.bpf;
1951 bpfconf.prog_file = StringRef::from_lit(PKGLIBDIR "/reuseport_kern.o");
1953 upstreamconf.congestion_controller = NGTCP2_CC_ALGO_CUBIC;
1955 upstreamconf.initial_rtt =
1956 static_cast<ev_tstamp>(NGTCP2_DEFAULT_INITIAL_RTT) / NGTCP2_SECONDS;
1959 if (RAND_bytes(quicconf.server_id.data(), quicconf.server_id.size()) != 1) {
1964 auto &http3conf = config->http3;
1966 auto &upstreamconf = http3conf.upstream;
1968 upstreamconf.max_concurrent_streams = 100;
1969 upstreamconf.window_size = 256_k;
1970 upstreamconf.connection_window_size = 1_m;
1971 upstreamconf.max_window_size = 6_m;
1972 upstreamconf.max_connection_window_size = 8_m;
1974 #endif // ENABLE_HTTP3
1976 auto &loggingconf = config->logging;
1978 auto &accessconf = loggingconf.access;
1980 parse_log_format(config->balloc, DEFAULT_ACCESSLOG_FORMAT);
1982 auto &errorconf = loggingconf.error;
1983 errorconf.file = StringRef::from_lit("/dev/stderr");
1986 loggingconf.syslog_facility = LOG_DAEMON;
1987 loggingconf.severity = NOTICE;
1989 auto &connconf = config->conn;
1991 auto &listenerconf = connconf.listener;
1993 // Default accept() backlog
1994 listenerconf.backlog = 65536;
1995 listenerconf.timeout.sleep = 30_s;
2000 auto &upstreamconf = connconf.upstream;
2002 auto &timeoutconf = upstreamconf.timeout;
2003 // Read timeout for HTTP2 upstream connection
2004 timeoutconf.http2_read = 3_min;
2006 // Read timeout for HTTP3 upstream connection
2007 timeoutconf.http3_read = 3_min;
2009 // Read timeout for non-HTTP2 upstream connection
2010 timeoutconf.read = 1_min;
2012 // Write timeout for HTTP2/non-HTTP2 upstream connection
2013 timeoutconf.write = 30_s;
2015 // Keep alive timeout for HTTP/1 upstream connection
2016 timeoutconf.idle_read = 1_min;
2021 connconf.downstream = std::make_shared<DownstreamConfig>();
2022 auto &downstreamconf = *connconf.downstream;
2024 auto &timeoutconf = downstreamconf.timeout;
2025 // Read/Write timeouts for downstream connection
2026 timeoutconf.read = 1_min;
2027 timeoutconf.write = 30_s;
2028 // Timeout for pooled (idle) connections
2029 timeoutconf.idle_read = 2_s;
2030 timeoutconf.connect = 30_s;
2031 timeoutconf.max_backoff = 120_s;
2034 downstreamconf.connections_per_host = 8;
2035 downstreamconf.request_buffer_size = 16_k;
2036 downstreamconf.response_buffer_size = 128_k;
2037 downstreamconf.family = AF_UNSPEC;
2040 auto &apiconf = config->api;
2041 apiconf.max_request_body = 32_m;
2043 auto &dnsconf = config->dns;
2045 auto &timeoutconf = dnsconf.timeout;
2046 timeoutconf.cache = 10_s;
2047 timeoutconf.lookup = 5_s;
2049 dnsconf.max_try = 2;
2055 void print_version(std::ostream &out) {
2056 out << "nghttpx nghttp2/" NGHTTP2_VERSION << std::endl;
2061 void print_usage(std::ostream &out) {
2062 out << R"(Usage: nghttpx [OPTIONS]... [<PRIVATE_KEY> <CERT>]
2063 A reverse proxy for HTTP/3, HTTP/2, and HTTP/1.)"
2069 void print_help(std::ostream &out) {
2070 auto config = get_config();
2075 Set path to server's private key. Required unless
2076 "no-tls" parameter is used in --frontend option.
2077 <CERT> Set path to server's certificate. Required unless
2078 "no-tls" parameter is used in --frontend option. To
2079 make OCSP stapling work, this must be an absolute path.
2082 The options are categorized into several groups.
2085 -b, --backend=(<HOST>,<PORT>|unix:<PATH>)[;[<PATTERN>[:...]][[;<PARAM>]...]
2087 Set backend host and port. The multiple backend
2088 addresses are accepted by repeating this option. UNIX
2089 domain socket can be specified by prefixing path name
2090 with "unix:" (e.g., unix:/var/run/backend.sock).
2092 Optionally, if <PATTERN>s are given, the backend address
2093 is only used if request matches the pattern. The
2094 pattern matching is closely designed to ServeMux in
2095 net/http package of Go programming language. <PATTERN>
2096 consists of path, host + path or just host. The path
2097 must start with "/". If it ends with "/", it matches
2098 all request path in its subtree. To deal with the
2099 request to the directory without trailing slash, the
2100 path which ends with "/" also matches the request path
2101 which only lacks trailing '/' (e.g., path "/foo/"
2102 matches request path "/foo"). If it does not end with
2103 "/", it performs exact match against the request path.
2104 If host is given, it performs a match against the
2105 request host. For a request received on the frontend
2106 listener with "sni-fwd" parameter enabled, SNI host is
2107 used instead of a request host. If host alone is given,
2108 "/" is appended to it, so that it matches all request
2109 paths under the host (e.g., specifying "nghttp2.org"
2110 equals to "nghttp2.org/"). CONNECT method is treated
2111 specially. It does not have path, and we don't allow
2112 empty path. To workaround this, we assume that CONNECT
2113 method has "/" as path.
2115 Patterns with host take precedence over patterns with
2116 just path. Then, longer patterns take precedence over
2119 Host can include "*" in the left most position to
2120 indicate wildcard match (only suffix match is done).
2121 The "*" must match at least one character. For example,
2122 host pattern "*.nghttp2.org" matches against
2123 "www.nghttp2.org" and "git.ngttp2.org", but does not
2124 match against "nghttp2.org". The exact hosts match
2125 takes precedence over the wildcard hosts match.
2127 If path part ends with "*", it is treated as wildcard
2128 path. The wildcard path behaves differently from the
2129 normal path. For normal path, match is made around the
2130 boundary of path component separator,"/". On the other
2131 hand, the wildcard path does not take into account the
2132 path component separator. All paths which include the
2133 wildcard path without last "*" as prefix, and are
2134 strictly longer than wildcard path without last "*" are
2135 matched. "*" must match at least one character. For
2136 example, the pattern "/foo*" matches "/foo/" and
2137 "/foobar". But it does not match "/foo", or "/fo".
2139 If <PATTERN> is omitted or empty string, "/" is used as
2140 pattern, which matches all request paths (catch-all
2141 pattern). The catch-all backend must be given.
2143 When doing a match, nghttpx made some normalization to
2144 pattern, request host and path. For host part, they are
2145 converted to lower case. For path part, percent-encoded
2146 unreserved characters defined in RFC 3986 are decoded,
2147 and any dot-segments (".." and ".") are resolved and
2150 For example, -b'127.0.0.1,8080;nghttp2.org/httpbin/'
2151 matches the request host "nghttp2.org" and the request
2152 path "/httpbin/get", but does not match the request host
2153 "nghttp2.org" and the request path "/index.html".
2155 The multiple <PATTERN>s can be specified, delimiting
2156 them by ":". Specifying
2157 -b'127.0.0.1,8080;nghttp2.org:www.nghttp2.org' has the
2158 same effect to specify -b'127.0.0.1,8080;nghttp2.org'
2159 and -b'127.0.0.1,8080;www.nghttp2.org'.
2161 The backend addresses sharing same <PATTERN> are grouped
2162 together forming load balancing group.
2164 Several parameters <PARAM> are accepted after <PATTERN>.
2165 The parameters are delimited by ";". The available
2166 parameters are: "proto=<PROTO>", "tls",
2167 "sni=<SNI_HOST>", "fall=<N>", "rise=<N>",
2168 "affinity=<METHOD>", "dns", "redirect-if-not-tls",
2169 "upgrade-scheme", "mruby=<PATH>",
2170 "read-timeout=<DURATION>", "write-timeout=<DURATION>",
2171 "group=<GROUP>", "group-weight=<N>", "weight=<N>", and
2172 "dnf". The parameter consists of keyword, and
2173 optionally followed by "=" and value. For example, the
2174 parameter "proto=h2" consists of the keyword "proto" and
2175 value "h2". The parameter "tls" consists of the keyword
2176 "tls" without value. Each parameter is described as
2179 The backend application protocol can be specified using
2180 optional "proto" parameter, and in the form of
2181 "proto=<PROTO>". <PROTO> should be one of the following
2182 list without quotes: "h2", "http/1.1". The default
2183 value of <PROTO> is "http/1.1". Note that usually "h2"
2184 refers to HTTP/2 over TLS. But in this option, it may
2185 mean HTTP/2 over cleartext TCP unless "tls" keyword is
2188 TLS can be enabled by specifying optional "tls"
2189 parameter. TLS is not enabled by default.
2191 With "sni=<SNI_HOST>" parameter, it can override the TLS
2192 SNI field value with given <SNI_HOST>. This will
2193 default to the backend <HOST> name
2195 The feature to detect whether backend is online or
2196 offline can be enabled using optional "fall" and "rise"
2197 parameters. Using "fall=<N>" parameter, if nghttpx
2198 cannot connect to a this backend <N> times in a row,
2199 this backend is assumed to be offline, and it is
2200 excluded from load balancing. If <N> is 0, this backend
2201 never be excluded from load balancing whatever times
2202 nghttpx cannot connect to it, and this is the default.
2203 There is also "rise=<N>" parameter. After backend was
2204 excluded from load balancing group, nghttpx periodically
2205 attempts to make a connection to the failed backend, and
2206 if the connection is made successfully <N> times in a
2207 row, the backend is assumed to be online, and it is now
2208 eligible for load balancing target. If <N> is 0, a
2209 backend is permanently offline, once it goes in that
2210 state, and this is the default behaviour.
2212 The session affinity is enabled using
2213 "affinity=<METHOD>" parameter. If "ip" is given in
2214 <METHOD>, client IP based session affinity is enabled.
2215 If "cookie" is given in <METHOD>, cookie based session
2216 affinity is enabled. If "none" is given in <METHOD>,
2217 session affinity is disabled, and this is the default.
2218 The session affinity is enabled per <PATTERN>. If at
2219 least one backend has "affinity" parameter, and its
2220 <METHOD> is not "none", session affinity is enabled for
2221 all backend servers sharing the same <PATTERN>. It is
2222 advised to set "affinity" parameter to all backend
2223 explicitly if session affinity is desired. The session
2224 affinity may break if one of the backend gets
2225 unreachable, or backend settings are reloaded or
2228 If "affinity=cookie" is used, the additional
2229 configuration is required.
2230 "affinity-cookie-name=<NAME>" must be used to specify a
2231 name of cookie to use. Optionally,
2232 "affinity-cookie-path=<PATH>" can be used to specify a
2233 path which cookie is applied. The optional
2234 "affinity-cookie-secure=<SECURE>" controls the Secure
2235 attribute of a cookie. The default value is "auto", and
2236 the Secure attribute is determined by a request scheme.
2237 If a request scheme is "https", then Secure attribute is
2238 set. Otherwise, it is not set. If <SECURE> is "yes",
2239 the Secure attribute is always set. If <SECURE> is
2240 "no", the Secure attribute is always omitted.
2242 By default, name resolution of backend host name is done
2243 at start up, or reloading configuration. If "dns"
2244 parameter is given, name resolution takes place
2245 dynamically. This is useful if backend address changes
2246 frequently. If "dns" is given, name resolution of
2247 backend host name at start up, or reloading
2248 configuration is skipped.
2250 If "redirect-if-not-tls" parameter is used, the matched
2251 backend requires that frontend connection is TLS
2252 encrypted. If it isn't, nghttpx responds to the request
2253 with 308 status code, and https URI the client should
2254 use instead is included in Location header field. The
2255 port number in redirect URI is 443 by default, and can
2256 be changed using --redirect-https-port option. If at
2257 least one backend has "redirect-if-not-tls" parameter,
2258 this feature is enabled for all backend servers sharing
2259 the same <PATTERN>. It is advised to set
2260 "redirect-if-no-tls" parameter to all backends
2261 explicitly if this feature is desired.
2263 If "upgrade-scheme" parameter is used along with "tls"
2264 parameter, HTTP/2 :scheme pseudo header field is changed
2265 to "https" from "http" when forwarding a request to this
2266 particular backend. This is a workaround for a backend
2267 server which requires "https" :scheme pseudo header
2268 field on TLS encrypted connection.
2270 "mruby=<PATH>" parameter specifies a path to mruby
2271 script file which is invoked when this pattern is
2272 matched. All backends which share the same pattern must
2273 have the same mruby path.
2275 "read-timeout=<DURATION>" and "write-timeout=<DURATION>"
2276 parameters specify the read and write timeout of the
2277 backend connection when this pattern is matched. All
2278 backends which share the same pattern must have the same
2279 timeouts. If these timeouts are entirely omitted for a
2280 pattern, --backend-read-timeout and
2281 --backend-write-timeout are used.
2283 "group=<GROUP>" parameter specifies the name of group
2284 this backend address belongs to. By default, it belongs
2285 to the unnamed default group. The name of group is
2286 unique per pattern. "group-weight=<N>" parameter
2287 specifies the weight of the group. The higher weight
2288 gets more frequently selected by the load balancing
2289 algorithm. <N> must be [1, 256] inclusive. The weight
2290 8 has 4 times more weight than 2. <N> must be the same
2291 for all addresses which share the same <GROUP>. If
2292 "group-weight" is omitted in an address, but the other
2293 address which belongs to the same group specifies
2294 "group-weight", its weight is used. If no
2295 "group-weight" is specified for all addresses, the
2296 weight of a group becomes 1. "group" and "group-weight"
2297 are ignored if session affinity is enabled.
2299 "weight=<N>" parameter specifies the weight of the
2300 backend address inside a group which this address
2301 belongs to. The higher weight gets more frequently
2302 selected by the load balancing algorithm. <N> must be
2303 [1, 256] inclusive. The weight 8 has 4 times more
2304 weight than weight 2. If this parameter is omitted,
2305 weight becomes 1. "weight" is ignored if session
2306 affinity is enabled.
2308 If "dnf" parameter is specified, an incoming request is
2309 not forwarded to a backend and just consumed along with
2310 the request body (actually a backend server never be
2311 contacted). It is expected that the HTTP response is
2312 generated by mruby script (see "mruby=<PATH>" parameter
2313 above). "dnf" is an abbreviation of "do not forward".
2315 Since ";" and ":" are used as delimiter, <PATTERN> must
2316 not contain these characters. In order to include ":"
2317 in <PATTERN>, one has to specify "%3A" (which is
2318 percent-encoded from of ":") instead. Since ";" has
2319 special meaning in shell, the option value must be
2323 << DEFAULT_DOWNSTREAM_HOST << "," << DEFAULT_DOWNSTREAM_PORT << R"(
2324 -f, --frontend=(<HOST>,<PORT>|unix:<PATH>)[[;<PARAM>]...]
2325 Set frontend host and port. If <HOST> is '*', it
2326 assumes all addresses including both IPv4 and IPv6.
2327 UNIX domain socket can be specified by prefixing path
2328 name with "unix:" (e.g., unix:/var/run/nghttpx.sock).
2329 This option can be used multiple times to listen to
2332 This option can take 0 or more parameters, which are
2333 described below. Note that "api" and "healthmon"
2334 parameters are mutually exclusive.
2336 Optionally, TLS can be disabled by specifying "no-tls"
2337 parameter. TLS is enabled by default.
2339 If "sni-fwd" parameter is used, when performing a match
2340 to select a backend server, SNI host name received from
2341 the client is used instead of the request host. See
2342 --backend option about the pattern match.
2344 To make this frontend as API endpoint, specify "api"
2345 parameter. This is disabled by default. It is
2346 important to limit the access to the API frontend.
2347 Otherwise, someone may change the backend server, and
2348 break your services, or expose confidential information
2349 to the outside the world.
2351 To make this frontend as health monitor endpoint,
2352 specify "healthmon" parameter. This is disabled by
2353 default. Any requests which come through this address
2354 are replied with 200 HTTP status, without no body.
2356 To accept PROXY protocol version 1 and 2 on frontend
2357 connection, specify "proxyproto" parameter. This is
2358 disabled by default.
2360 To receive HTTP/3 (QUIC) traffic, specify "quic"
2361 parameter. It makes nghttpx listen on UDP port rather
2362 than TCP port. UNIX domain socket, "api", and
2363 "healthmon" parameters cannot be used with "quic"
2368 Set listen backlog size.
2370 << config->conn.listener.backlog << R"(
2371 --backend-address-family=(auto|IPv4|IPv6)
2372 Specify address family of backend connections. If
2373 "auto" is given, both IPv4 and IPv6 are considered. If
2374 "IPv4" is given, only IPv4 address is considered. If
2375 "IPv6" is given, only IPv6 address is considered.
2377 --backend-http-proxy-uri=<URI>
2378 Specify proxy URI in the form
2379 http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a proxy
2380 requires authentication, specify <USER> and <PASS>.
2381 Note that they must be properly percent-encoded. This
2382 proxy is used when the backend connection is HTTP/2.
2383 First, make a CONNECT request to the proxy and it
2384 connects to the backend on behalf of nghttpx. This
2385 forms tunnel. After that, nghttpx performs SSL/TLS
2386 handshake with the downstream through the tunnel. The
2387 timeouts when connecting and making CONNECT request can
2388 be specified by --backend-read-timeout and
2389 --backend-write-timeout options.
2393 Set the number of worker threads.
2395 << config->num_worker << R"(
2397 Run everything in one thread inside the worker process.
2398 This feature is provided for better debugging
2399 experience, or for the platforms which lack thread
2400 support. If threading is disabled, this option is
2403 Set maximum average read rate on frontend connection.
2404 Setting 0 to this option means read rate is unlimited.
2406 << config->conn.upstream.ratelimit.read.rate << R"(
2408 Set maximum read burst size on frontend connection.
2409 Setting 0 to this option means read burst size is
2412 << config->conn.upstream.ratelimit.read.burst << R"(
2414 Set maximum average write rate on frontend connection.
2415 Setting 0 to this option means write rate is unlimited.
2417 << config->conn.upstream.ratelimit.write.rate << R"(
2418 --write-burst=<SIZE>
2419 Set maximum write burst size on frontend connection.
2420 Setting 0 to this option means write burst size is
2423 << config->conn.upstream.ratelimit.write.burst << R"(
2424 --worker-read-rate=<SIZE>
2425 Set maximum average read rate on frontend connection per
2426 worker. Setting 0 to this option means read rate is
2427 unlimited. Not implemented yet.
2429 --worker-read-burst=<SIZE>
2430 Set maximum read burst size on frontend connection per
2431 worker. Setting 0 to this option means read burst size
2432 is unlimited. Not implemented yet.
2434 --worker-write-rate=<SIZE>
2435 Set maximum average write rate on frontend connection
2436 per worker. Setting 0 to this option means write rate
2437 is unlimited. Not implemented yet.
2439 --worker-write-burst=<SIZE>
2440 Set maximum write burst size on frontend connection per
2441 worker. Setting 0 to this option means write burst size
2442 is unlimited. Not implemented yet.
2444 --worker-frontend-connections=<N>
2445 Set maximum number of simultaneous connections frontend
2446 accepts. Setting 0 means unlimited.
2448 << config->conn.upstream.worker_connections << R"(
2449 --backend-connections-per-host=<N>
2450 Set maximum number of backend concurrent connections
2451 (and/or streams in case of HTTP/2) per origin host.
2452 This option is meaningful when --http2-proxy option is
2453 used. The origin host is determined by authority
2454 portion of request URI (or :authority header field for
2455 HTTP/2). To limit the number of connections per
2456 frontend for default mode, use
2457 --backend-connections-per-frontend.
2459 << config->conn.downstream->connections_per_host << R"(
2460 --backend-connections-per-frontend=<N>
2461 Set maximum number of backend concurrent connections
2462 (and/or streams in case of HTTP/2) per frontend. This
2463 option is only used for default mode. 0 means
2464 unlimited. To limit the number of connections per host
2465 with --http2-proxy option, use
2466 --backend-connections-per-host.
2468 << config->conn.downstream->connections_per_frontend << R"(
2470 Set maximum number of open files (RLIMIT_NOFILE) to <N>.
2471 If 0 is given, nghttpx does not set the limit.
2473 << config->rlimit_nofile << R"(
2474 --rlimit-memlock=<N>
2475 Set maximum number of bytes of memory that may be locked
2476 into RAM. If 0 is given, nghttpx does not set the
2479 << config->rlimit_memlock << R"(
2480 --backend-request-buffer=<SIZE>
2481 Set buffer size used to store backend request.
2483 << util::utos_unit(config->conn.downstream->request_buffer_size) << R"(
2484 --backend-response-buffer=<SIZE>
2485 Set buffer size used to store backend response.
2487 << util::utos_unit(config->conn.downstream->response_buffer_size) << R"(
2489 Enables "TCP Fast Open" for the listening socket and
2490 limits the maximum length for the queue of connections
2491 that have not yet completed the three-way handshake. If
2492 value is 0 then fast open is disabled.
2494 << config->conn.listener.fastopen << R"(
2495 --no-kqueue Don't use kqueue. This option is only applicable for
2496 the platforms which have kqueue. For other platforms,
2497 this option will be simply ignored.
2500 --frontend-http2-read-timeout=<DURATION>
2501 Specify read timeout for HTTP/2 frontend connection.
2503 << util::duration_str(config->conn.upstream.timeout.http2_read) << R"(
2504 --frontend-http3-read-timeout=<DURATION>
2505 Specify read timeout for HTTP/3 frontend connection.
2507 << util::duration_str(config->conn.upstream.timeout.http3_read) << R"(
2508 --frontend-read-timeout=<DURATION>
2509 Specify read timeout for HTTP/1.1 frontend connection.
2511 << util::duration_str(config->conn.upstream.timeout.read) << R"(
2512 --frontend-write-timeout=<DURATION>
2513 Specify write timeout for all frontend connections.
2515 << util::duration_str(config->conn.upstream.timeout.write) << R"(
2516 --frontend-keep-alive-timeout=<DURATION>
2517 Specify keep-alive timeout for frontend HTTP/1
2520 << util::duration_str(config->conn.upstream.timeout.idle_read) << R"(
2521 --stream-read-timeout=<DURATION>
2522 Specify read timeout for HTTP/2 streams. 0 means no
2525 << util::duration_str(config->http2.timeout.stream_read) << R"(
2526 --stream-write-timeout=<DURATION>
2527 Specify write timeout for HTTP/2 streams. 0 means no
2530 << util::duration_str(config->http2.timeout.stream_write) << R"(
2531 --backend-read-timeout=<DURATION>
2532 Specify read timeout for backend connection.
2534 << util::duration_str(config->conn.downstream->timeout.read) << R"(
2535 --backend-write-timeout=<DURATION>
2536 Specify write timeout for backend connection.
2538 << util::duration_str(config->conn.downstream->timeout.write) << R"(
2539 --backend-connect-timeout=<DURATION>
2540 Specify timeout before establishing TCP connection to
2543 << util::duration_str(config->conn.downstream->timeout.connect) << R"(
2544 --backend-keep-alive-timeout=<DURATION>
2545 Specify keep-alive timeout for backend HTTP/1
2548 << util::duration_str(config->conn.downstream->timeout.idle_read) << R"(
2549 --listener-disable-timeout=<DURATION>
2550 After accepting connection failed, connection listener
2551 is disabled for a given amount of time. Specifying 0
2552 disables this feature.
2554 << util::duration_str(config->conn.listener.timeout.sleep) << R"(
2555 --frontend-http2-setting-timeout=<DURATION>
2556 Specify timeout before SETTINGS ACK is received from
2559 << util::duration_str(config->http2.upstream.timeout.settings) << R"(
2560 --backend-http2-settings-timeout=<DURATION>
2561 Specify timeout before SETTINGS ACK is received from
2564 << util::duration_str(config->http2.downstream.timeout.settings) << R"(
2565 --backend-max-backoff=<DURATION>
2566 Specify maximum backoff interval. This is used when
2567 doing health check against offline backend (see "fail"
2568 parameter in --backend option). It is also used to
2569 limit the maximum interval to temporarily disable
2570 backend when nghttpx failed to connect to it. These
2571 intervals are calculated using exponential backoff, and
2572 consecutive failed attempts increase the interval. This
2573 option caps its maximum value.
2575 << util::duration_str(config->conn.downstream->timeout.max_backoff) << R"(
2579 Set allowed cipher list for frontend connection. The
2580 format of the string is described in OpenSSL ciphers(1).
2581 This option sets cipher suites for TLSv1.2 or earlier.
2582 Use --tls13-ciphers for TLSv1.3.
2584 << config->tls.ciphers << R"(
2585 --tls13-ciphers=<SUITE>
2586 Set allowed cipher list for frontend connection. The
2587 format of the string is described in OpenSSL ciphers(1).
2588 This option sets cipher suites for TLSv1.3. Use
2589 --ciphers for TLSv1.2 or earlier.
2591 << config->tls.tls13_ciphers << R"(
2592 --client-ciphers=<SUITE>
2593 Set allowed cipher list for backend connection. The
2594 format of the string is described in OpenSSL ciphers(1).
2595 This option sets cipher suites for TLSv1.2 or earlier.
2596 Use --tls13-client-ciphers for TLSv1.3.
2598 << config->tls.client.ciphers << R"(
2599 --tls13-client-ciphers=<SUITE>
2600 Set allowed cipher list for backend connection. The
2601 format of the string is described in OpenSSL ciphers(1).
2602 This option sets cipher suites for TLSv1.3. Use
2603 --tls13-client-ciphers for TLSv1.2 or earlier.
2605 << config->tls.client.tls13_ciphers << R"(
2606 --ecdh-curves=<LIST>
2607 Set supported curve list for frontend connections.
2608 <LIST> is a colon separated list of curve NID or names
2609 in the preference order. The supported curves depend on
2610 the linked OpenSSL library. This function requires
2613 << config->tls.ecdh_curves << R"(
2615 Don't verify backend server's certificate if TLS is
2616 enabled for backend connections.
2618 Set path to trusted CA certificate file. It is used in
2619 backend TLS connections to verify peer's certificate.
2620 It is also used to verify OCSP response from the script
2621 set by --fetch-ocsp-response-file. The file must be in
2622 PEM format. It can contain multiple certificates. If
2623 the linked OpenSSL is configured to load system wide
2624 certificates, they are loaded at startup regardless of
2626 --private-key-passwd-file=<PATH>
2627 Path to file that contains password for the server's
2628 private key. If none is given and the private key is
2629 password protected it'll be requested interactively.
2630 --subcert=<KEYPATH>:<CERTPATH>[[;<PARAM>]...]
2631 Specify additional certificate and private key file.
2632 nghttpx will choose certificates based on the hostname
2633 indicated by client using TLS SNI extension. If nghttpx
2634 is built with OpenSSL >= 1.0.2, the shared elliptic
2635 curves (e.g., P-256) between client and server are also
2636 taken into consideration. This allows nghttpx to send
2637 ECDSA certificate to modern clients, while sending RSA
2638 based certificate to older clients. This option can be
2639 used multiple times. To make OCSP stapling work,
2640 <CERTPATH> must be absolute path.
2642 Additional parameter can be specified in <PARAM>. The
2643 available <PARAM> is "sct-dir=<DIR>".
2645 "sct-dir=<DIR>" specifies the path to directory which
2646 contains *.sct files for TLS
2647 signed_certificate_timestamp extension (RFC 6962). This
2648 feature requires OpenSSL >= 1.0.2. See also
2649 --tls-sct-dir option.
2650 --dh-param-file=<PATH>
2651 Path to file that contains DH parameters in PEM format.
2652 Without this option, DHE cipher suites are not
2655 Comma delimited list of ALPN protocol identifier sorted
2656 in the order of preference. That means most desirable
2657 protocol comes first. This is used in both ALPN and
2658 NPN. The parameter must be delimited by a single comma
2659 only and any white spaces are treated as a part of
2665 Require and verify client certificate.
2666 --verify-client-cacert=<PATH>
2667 Path to file that contains CA certificates to verify
2668 client certificate. The file must be in PEM format. It
2669 can contain multiple certificates.
2670 --verify-client-tolerate-expired
2671 Accept expired client certificate. Operator should
2672 handle the expired client certificate by some means
2673 (e.g., mruby script). Otherwise, this option might
2674 cause a security risk.
2675 --client-private-key-file=<PATH>
2676 Path to file that contains client private key used in
2677 backend client authentication.
2678 --client-cert-file=<PATH>
2679 Path to file that contains client certificate used in
2680 backend client authentication.
2681 --tls-min-proto-version=<VER>
2682 Specify minimum SSL/TLS protocol. The name matching is
2683 done in case-insensitive manner. The versions between
2684 --tls-min-proto-version and --tls-max-proto-version are
2685 enabled. If the protocol list advertised by client does
2686 not overlap this range, you will receive the error
2687 message "unknown protocol". If a protocol version lower
2688 than TLSv1.2 is specified, make sure that the compatible
2689 ciphers are included in --ciphers option. The default
2690 cipher list only includes ciphers compatible with
2691 TLSv1.2 or above. The available versions are:
2693 #ifdef TLS1_3_VERSION
2695 #endif // TLS1_3_VERSION
2696 "TLSv1.2, TLSv1.1, and TLSv1.0"
2699 << DEFAULT_TLS_MIN_PROTO_VERSION
2701 --tls-max-proto-version=<VER>
2702 Specify maximum SSL/TLS protocol. The name matching is
2703 done in case-insensitive manner. The versions between
2704 --tls-min-proto-version and --tls-max-proto-version are
2705 enabled. If the protocol list advertised by client does
2706 not overlap this range, you will receive the error
2707 message "unknown protocol". The available versions are:
2709 #ifdef TLS1_3_VERSION
2711 #endif // TLS1_3_VERSION
2712 "TLSv1.2, TLSv1.1, and TLSv1.0"
2715 << DEFAULT_TLS_MAX_PROTO_VERSION << R"(
2716 --tls-ticket-key-file=<PATH>
2717 Path to file that contains random data to construct TLS
2718 session ticket parameters. If aes-128-cbc is given in
2719 --tls-ticket-key-cipher, the file must contain exactly
2720 48 bytes. If aes-256-cbc is given in
2721 --tls-ticket-key-cipher, the file must contain exactly
2722 80 bytes. This options can be used repeatedly to
2723 specify multiple ticket parameters. If several files
2724 are given, only the first key is used to encrypt TLS
2725 session tickets. Other keys are accepted but server
2726 will issue new session ticket with first key. This
2727 allows session key rotation. Please note that key
2728 rotation does not occur automatically. User should
2729 rearrange files or change options values and restart
2730 nghttpx gracefully. If opening or reading given file
2731 fails, all loaded keys are discarded and it is treated
2732 as if none of this option is given. If this option is
2733 not given or an error occurred while opening or reading
2734 a file, key is generated every 1 hour internally and
2735 they are valid for 12 hours. This is recommended if
2736 ticket key sharing between nghttpx instances is not
2738 --tls-ticket-key-memcached=<HOST>,<PORT>[;tls]
2739 Specify address of memcached server to get TLS ticket
2740 keys for session resumption. This enables shared TLS
2741 ticket key between multiple nghttpx instances. nghttpx
2742 does not set TLS ticket key to memcached. The external
2743 ticket key generator is required. nghttpx just gets TLS
2744 ticket keys from memcached, and use them, possibly
2745 replacing current set of keys. It is up to extern TLS
2746 ticket key generator to rotate keys frequently. See
2747 "TLS SESSION TICKET RESUMPTION" section in manual page
2748 to know the data format in memcached entry. Optionally,
2749 memcached connection can be encrypted with TLS by
2750 specifying "tls" parameter.
2751 --tls-ticket-key-memcached-address-family=(auto|IPv4|IPv6)
2752 Specify address family of memcached connections to get
2753 TLS ticket keys. If "auto" is given, both IPv4 and IPv6
2754 are considered. If "IPv4" is given, only IPv4 address
2755 is considered. If "IPv6" is given, only IPv6 address is
2758 --tls-ticket-key-memcached-interval=<DURATION>
2759 Set interval to get TLS ticket keys from memcached.
2761 << util::duration_str(config->tls.ticket.memcached.interval) << R"(
2762 --tls-ticket-key-memcached-max-retry=<N>
2763 Set maximum number of consecutive retries before
2764 abandoning TLS ticket key retrieval. If this number is
2765 reached, the attempt is considered as failure, and
2766 "failure" count is incremented by 1, which contributed
2767 to the value controlled
2768 --tls-ticket-key-memcached-max-fail option.
2770 << config->tls.ticket.memcached.max_retry << R"(
2771 --tls-ticket-key-memcached-max-fail=<N>
2772 Set maximum number of consecutive failure before
2773 disabling TLS ticket until next scheduled key retrieval.
2775 << config->tls.ticket.memcached.max_fail << R"(
2776 --tls-ticket-key-cipher=<CIPHER>
2777 Specify cipher to encrypt TLS session ticket. Specify
2778 either aes-128-cbc or aes-256-cbc. By default,
2779 aes-128-cbc is used.
2780 --tls-ticket-key-memcached-cert-file=<PATH>
2781 Path to client certificate for memcached connections to
2782 get TLS ticket keys.
2783 --tls-ticket-key-memcached-private-key-file=<PATH>
2784 Path to client private key for memcached connections to
2785 get TLS ticket keys.
2786 --fetch-ocsp-response-file=<PATH>
2787 Path to fetch-ocsp-response script file. It should be
2790 << config->tls.ocsp.fetch_ocsp_response_file << R"(
2791 --ocsp-update-interval=<DURATION>
2792 Set interval to update OCSP response cache.
2794 << util::duration_str(config->tls.ocsp.update_interval) << R"(
2796 Start accepting connections after initial attempts to
2797 get OCSP responses finish. It does not matter some of
2798 the attempts fail. This feature is useful if OCSP
2799 responses must be available before accepting
2802 nghttpx does not verify OCSP response.
2803 --no-ocsp Disable OCSP stapling.
2804 --tls-session-cache-memcached=<HOST>,<PORT>[;tls]
2805 Specify address of memcached server to store session
2806 cache. This enables shared session cache between
2807 multiple nghttpx instances. Optionally, memcached
2808 connection can be encrypted with TLS by specifying "tls"
2810 --tls-session-cache-memcached-address-family=(auto|IPv4|IPv6)
2811 Specify address family of memcached connections to store
2812 session cache. If "auto" is given, both IPv4 and IPv6
2813 are considered. If "IPv4" is given, only IPv4 address
2814 is considered. If "IPv6" is given, only IPv6 address is
2817 --tls-session-cache-memcached-cert-file=<PATH>
2818 Path to client certificate for memcached connections to
2819 store session cache.
2820 --tls-session-cache-memcached-private-key-file=<PATH>
2821 Path to client private key for memcached connections to
2822 store session cache.
2823 --tls-dyn-rec-warmup-threshold=<SIZE>
2824 Specify the threshold size for TLS dynamic record size
2825 behaviour. During a TLS session, after the threshold
2826 number of bytes have been written, the TLS record size
2827 will be increased to the maximum allowed (16K). The max
2828 record size will continue to be used on the active TLS
2829 session. After --tls-dyn-rec-idle-timeout has elapsed,
2830 the record size is reduced to 1300 bytes. Specify 0 to
2831 always use the maximum record size, regardless of idle
2832 period. This behaviour applies to all TLS based
2833 frontends, and TLS HTTP/2 backends.
2835 << util::utos_unit(config->tls.dyn_rec.warmup_threshold) << R"(
2836 --tls-dyn-rec-idle-timeout=<DURATION>
2837 Specify TLS dynamic record size behaviour timeout. See
2838 --tls-dyn-rec-warmup-threshold for more information.
2839 This behaviour applies to all TLS based frontends, and
2840 TLS HTTP/2 backends.
2842 << util::duration_str(config->tls.dyn_rec.idle_timeout) << R"(
2843 --no-http2-cipher-block-list
2844 Allow block listed cipher suite on frontend HTTP/2
2846 https://tools.ietf.org/html/rfc7540#appendix-A for the
2847 complete HTTP/2 cipher suites block list.
2848 --client-no-http2-cipher-block-list
2849 Allow block listed cipher suite on backend HTTP/2
2851 https://tools.ietf.org/html/rfc7540#appendix-A for the
2852 complete HTTP/2 cipher suites block list.
2854 Specifies the directory where *.sct files exist. All
2855 *.sct files in <DIR> are read, and sent as
2856 extension_data of TLS signed_certificate_timestamp (RFC
2857 6962) to client. These *.sct files are for the
2858 certificate specified in positional command-line
2859 argument <CERT>, or certificate option in configuration
2860 file. For additional certificates, use --subcert
2861 option. This option requires OpenSSL >= 1.0.2.
2862 --psk-secrets=<PATH>
2863 Read list of PSK identity and secrets from <PATH>. This
2864 is used for frontend connection. The each line of input
2865 file is formatted as <identity>:<hex-secret>, where
2866 <identity> is PSK identity, and <hex-secret> is secret
2867 in hex. An empty line, and line which starts with '#'
2868 are skipped. The default enabled cipher list might not
2869 contain any PSK cipher suite. In that case, desired PSK
2870 cipher suites must be enabled using --ciphers option.
2871 The desired PSK cipher suite may be block listed by
2872 HTTP/2. To use those cipher suites with HTTP/2,
2873 consider to use --no-http2-cipher-block-list option.
2874 But be aware its implications.
2875 --client-psk-secrets=<PATH>
2876 Read PSK identity and secrets from <PATH>. This is used
2877 for backend connection. The each line of input file is
2878 formatted as <identity>:<hex-secret>, where <identity>
2879 is PSK identity, and <hex-secret> is secret in hex. An
2880 empty line, and line which starts with '#' are skipped.
2881 The first identity and secret pair encountered is used.
2882 The default enabled cipher list might not contain any
2883 PSK cipher suite. In that case, desired PSK cipher
2884 suites must be enabled using --client-ciphers option.
2885 The desired PSK cipher suite may be block listed by
2886 HTTP/2. To use those cipher suites with HTTP/2,
2887 consider to use --client-no-http2-cipher-block-list
2888 option. But be aware its implications.
2889 --tls-no-postpone-early-data
2890 By default, except for QUIC connections, nghttpx
2891 postpones forwarding HTTP requests sent in early data,
2892 including those sent in partially in it, until TLS
2893 handshake finishes. If all backend server recognizes
2894 "Early-Data" header field, using this option makes
2895 nghttpx not postpone forwarding request and get full
2896 potential of 0-RTT data.
2897 --tls-max-early-data=<SIZE>
2898 Sets the maximum amount of 0-RTT data that server
2901 << util::utos_unit(config->tls.max_early_data) << R"(
2904 -c, --frontend-http2-max-concurrent-streams=<N>
2905 Set the maximum number of the concurrent streams in one
2906 frontend HTTP/2 session.
2908 << config->http2.upstream.max_concurrent_streams << R"(
2909 --backend-http2-max-concurrent-streams=<N>
2910 Set the maximum number of the concurrent streams in one
2911 backend HTTP/2 session. This sets maximum number of
2912 concurrent opened pushed streams. The maximum number of
2913 concurrent requests are set by a remote server.
2915 << config->http2.downstream.max_concurrent_streams << R"(
2916 --frontend-http2-window-size=<SIZE>
2917 Sets the per-stream initial window size of HTTP/2
2918 frontend connection.
2920 << config->http2.upstream.window_size << R"(
2921 --frontend-http2-connection-window-size=<SIZE>
2922 Sets the per-connection window size of HTTP/2 frontend
2925 << config->http2.upstream.connection_window_size << R"(
2926 --backend-http2-window-size=<SIZE>
2927 Sets the initial window size of HTTP/2 backend
2930 << config->http2.downstream.window_size << R"(
2931 --backend-http2-connection-window-size=<SIZE>
2932 Sets the per-connection window size of HTTP/2 backend
2935 << config->http2.downstream.connection_window_size << R"(
2936 --http2-no-cookie-crumbling
2937 Don't crumble cookie header field.
2939 Add at most <N> bytes to a HTTP/2 frame payload as
2940 padding. Specify 0 to disable padding. This option is
2941 meant for debugging purpose and not intended to enhance
2944 Disable HTTP/2 server push. Server push is supported by
2945 default mode and HTTP/2 frontend via Link header field.
2946 It is also supported if both frontend and backend are
2947 HTTP/2 in default mode. In this case, server push from
2948 backend session is relayed to frontend, and server push
2949 via Link header field is also supported.
2950 --frontend-http2-optimize-write-buffer-size
2951 (Experimental) Enable write buffer size optimization in
2952 frontend HTTP/2 TLS connection. This optimization aims
2953 to reduce write buffer size so that it only contains
2954 bytes which can send immediately. This makes server
2955 more responsive to prioritized HTTP/2 stream because the
2956 buffering of lower priority stream is reduced. This
2957 option is only effective on recent Linux platform.
2958 --frontend-http2-optimize-window-size
2959 (Experimental) Automatically tune connection level
2960 window size of frontend HTTP/2 TLS connection. If this
2961 feature is enabled, connection window size starts with
2962 the default window size, 65535 bytes. nghttpx
2963 automatically adjusts connection window size based on
2964 TCP receiving window size. The maximum window size is
2965 capped by the value specified by
2966 --frontend-http2-connection-window-size. Since the
2967 stream is subject to stream level window size, it should
2968 be adjusted using --frontend-http2-window-size option as
2969 well. This option is only effective on recent Linux
2971 --frontend-http2-encoder-dynamic-table-size=<SIZE>
2972 Specify the maximum dynamic table size of HPACK encoder
2973 in the frontend HTTP/2 connection. The decoder (client)
2974 specifies the maximum dynamic table size it accepts.
2975 Then the negotiated dynamic table size is the minimum of
2976 this option value and the value which client specified.
2978 << util::utos_unit(config->http2.upstream.encoder_dynamic_table_size)
2980 --frontend-http2-decoder-dynamic-table-size=<SIZE>
2981 Specify the maximum dynamic table size of HPACK decoder
2982 in the frontend HTTP/2 connection.
2984 << util::utos_unit(config->http2.upstream.decoder_dynamic_table_size)
2986 --backend-http2-encoder-dynamic-table-size=<SIZE>
2987 Specify the maximum dynamic table size of HPACK encoder
2988 in the backend HTTP/2 connection. The decoder (backend)
2989 specifies the maximum dynamic table size it accepts.
2990 Then the negotiated dynamic table size is the minimum of
2991 this option value and the value which backend specified.
2993 << util::utos_unit(config->http2.downstream.encoder_dynamic_table_size)
2995 --backend-http2-decoder-dynamic-table-size=<SIZE>
2996 Specify the maximum dynamic table size of HPACK decoder
2997 in the backend HTTP/2 connection.
2999 << util::utos_unit(config->http2.downstream.decoder_dynamic_table_size)
3004 Accept HTTP/2, and HTTP/1.1 over SSL/TLS. "no-tls"
3005 parameter is used in --frontend option, accept HTTP/2
3006 and HTTP/1.1 over cleartext TCP. The incoming HTTP/1.1
3007 connection can be upgraded to HTTP/2 through HTTP
3010 Like default mode, but enable forward proxy. This is so
3011 called HTTP/2 proxy mode.
3014 -L, --log-level=<LEVEL>
3015 Set the severity level of log output. <LEVEL> must be
3016 one of INFO, NOTICE, WARN, ERROR and FATAL.
3018 --accesslog-file=<PATH>
3019 Set path to write access log. To reopen file, send USR1
3022 Send access log to syslog. If this option is used,
3023 --accesslog-file option is ignored.
3024 --accesslog-format=<FORMAT>
3025 Specify format string for access log. The default
3026 format is combined format. The following variables are
3029 * $remote_addr: client IP address.
3030 * $time_local: local time in Common Log format.
3031 * $time_iso8601: local time in ISO 8601 format.
3032 * $request: HTTP request line.
3033 * $status: HTTP response status code.
3034 * $body_bytes_sent: the number of bytes sent to client
3036 * $http_<VAR>: value of HTTP request header <VAR> where
3037 '_' in <VAR> is replaced with '-'.
3038 * $remote_port: client port.
3039 * $server_port: server port.
3040 * $request_time: request processing time in seconds with
3041 milliseconds resolution.
3042 * $pid: PID of the running process.
3043 * $alpn: ALPN identifier of the protocol which generates
3044 the response. For HTTP/1, ALPN is always http/1.1,
3045 regardless of minor version.
3046 * $tls_cipher: cipher used for SSL/TLS connection.
3047 * $tls_client_fingerprint_sha256: SHA-256 fingerprint of
3049 * $tls_client_fingerprint_sha1: SHA-1 fingerprint of
3051 * $tls_client_subject_name: subject name in client
3053 * $tls_client_issuer_name: issuer name in client
3055 * $tls_client_serial: serial number in client
3057 * $tls_protocol: protocol for SSL/TLS connection.
3058 * $tls_session_id: session ID for SSL/TLS connection.
3059 * $tls_session_reused: "r" if SSL/TLS session was
3060 reused. Otherwise, "."
3061 * $tls_sni: SNI server name for SSL/TLS connection.
3062 * $backend_host: backend host used to fulfill the
3063 request. "-" if backend host is not available.
3064 * $backend_port: backend port used to fulfill the
3065 request. "-" if backend host is not available.
3066 * $method: HTTP method
3067 * $path: Request path including query. For CONNECT
3068 request, authority is recorded.
3069 * $path_without_query: $path up to the first '?'
3070 character. For CONNECT request, authority is
3072 * $protocol_version: HTTP version (e.g., HTTP/1.1,
3075 The variable can be enclosed by "{" and "}" for
3076 disambiguation (e.g., ${remote_addr}).
3079 << DEFAULT_ACCESSLOG_FORMAT << R"(
3080 --accesslog-write-early
3081 Write access log when response header fields are
3082 received from backend rather than when request
3083 transaction finishes.
3084 --errorlog-file=<PATH>
3085 Set path to write error log. To reopen file, send USR1
3086 signal to nghttpx. stderr will be redirected to the
3087 error log file unless --errorlog-syslog is used.
3089 << config->logging.error.file << R"(
3091 Send error log to syslog. If this option is used,
3092 --errorlog-file option is ignored.
3093 --syslog-facility=<FACILITY>
3094 Set syslog facility to <FACILITY>.
3096 << str_syslog_facility(config->logging.syslog_facility) << R"(
3099 --add-x-forwarded-for
3100 Append X-Forwarded-For header field to the downstream
3102 --strip-incoming-x-forwarded-for
3103 Strip X-Forwarded-For header field from inbound client
3105 --no-add-x-forwarded-proto
3106 Don't append additional X-Forwarded-Proto header field
3107 to the backend request. If inbound client sets
3108 X-Forwarded-Proto, and
3109 --no-strip-incoming-x-forwarded-proto option is used,
3110 they are passed to the backend.
3111 --no-strip-incoming-x-forwarded-proto
3112 Don't strip X-Forwarded-Proto header field from inbound
3114 --add-forwarded=<LIST>
3115 Append RFC 7239 Forwarded header field with parameters
3116 specified in comma delimited list <LIST>. The supported
3117 parameters are "by", "for", "host", and "proto". By
3118 default, the value of "by" and "for" parameters are
3119 obfuscated string. See --forwarded-by and
3120 --forwarded-for options respectively. Note that nghttpx
3121 does not translate non-standard X-Forwarded-* header
3122 fields into Forwarded header field, and vice versa.
3123 --strip-incoming-forwarded
3124 Strip Forwarded header field from inbound client
3126 --forwarded-by=(obfuscated|ip|<VALUE>)
3127 Specify the parameter value sent out with "by" parameter
3128 of Forwarded header field. If "obfuscated" is given,
3129 the string is randomly generated at startup. If "ip" is
3130 given, the interface address of the connection,
3131 including port number, is sent with "by" parameter. In
3132 case of UNIX domain socket, "localhost" is used instead
3133 of address and port. User can also specify the static
3134 obfuscated string. The limitation is that it must start
3135 with "_", and only consists of character set
3136 [A-Za-z0-9._-], as described in RFC 7239.
3138 --forwarded-for=(obfuscated|ip)
3139 Specify the parameter value sent out with "for"
3140 parameter of Forwarded header field. If "obfuscated" is
3141 given, the string is randomly generated for each client
3142 connection. If "ip" is given, the remote client address
3143 of the connection, without port number, is sent with
3144 "for" parameter. In case of UNIX domain socket,
3145 "localhost" is used instead of address.
3147 --no-via Don't append to Via header field. If Via header field
3148 is received, it is left unaltered.
3149 --no-strip-incoming-early-data
3150 Don't strip Early-Data header field from inbound client
3152 --no-location-rewrite
3153 Don't rewrite location header field in default mode.
3154 When --http2-proxy is used, location header field will
3155 not be altered regardless of this option.
3157 Rewrite host and :authority header fields in default
3158 mode. When --http2-proxy is used, these headers will
3159 not be altered regardless of this option.
3160 --altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
3161 Specify protocol ID, port, host and origin of
3162 alternative service. <HOST>, <ORIGIN> and <PARAMS> are
3163 optional. Empty <HOST> and <ORIGIN> are allowed and
3164 they are treated as nothing is specified. They are
3165 advertised in alt-svc header field only in HTTP/1.1
3166 frontend. This option can be used multiple times to
3167 specify multiple alternative services.
3168 Example: --altsvc="h2,443,,,ma=3600; persist=1'
3169 --http2-altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
3170 Just like --altsvc option, but this altsvc is only sent
3172 --add-request-header=<HEADER>
3173 Specify additional header field to add to request header
3174 set. This option just appends header field and won't
3175 replace anything already set. This option can be used
3176 several times to specify multiple header fields.
3177 Example: --add-request-header="foo: bar"
3178 --add-response-header=<HEADER>
3179 Specify additional header field to add to response
3180 header set. This option just appends header field and
3181 won't replace anything already set. This option can be
3182 used several times to specify multiple header fields.
3183 Example: --add-response-header="foo: bar"
3184 --request-header-field-buffer=<SIZE>
3185 Set maximum buffer size for incoming HTTP request header
3186 field list. This is the sum of header name and value in
3187 bytes. If trailer fields exist, they are counted
3188 towards this number.
3190 << util::utos_unit(config->http.request_header_field_buffer) << R"(
3191 --max-request-header-fields=<N>
3192 Set maximum number of incoming HTTP request header
3193 fields. If trailer fields exist, they are counted
3194 towards this number.
3196 << config->http.max_request_header_fields << R"(
3197 --response-header-field-buffer=<SIZE>
3198 Set maximum buffer size for incoming HTTP response
3199 header field list. This is the sum of header name and
3200 value in bytes. If trailer fields exist, they are
3201 counted towards this number.
3203 << util::utos_unit(config->http.response_header_field_buffer) << R"(
3204 --max-response-header-fields=<N>
3205 Set maximum number of incoming HTTP response header
3206 fields. If trailer fields exist, they are counted
3207 towards this number.
3209 << config->http.max_response_header_fields << R"(
3210 --error-page=(<CODE>|*)=<PATH>
3211 Set file path to custom error page served when nghttpx
3212 originally generates HTTP error status code <CODE>.
3213 <CODE> must be greater than or equal to 400, and at most
3214 599. If "*" is used instead of <CODE>, it matches all
3215 HTTP status code. If error status code comes from
3216 backend server, the custom error pages are not used.
3217 --server-name=<NAME>
3218 Change server response header field value to <NAME>.
3220 << config->http.server_name << R"(
3222 Don't rewrite server header field in default mode. When
3223 --http2-proxy is used, these headers will not be altered
3224 regardless of this option.
3225 --redirect-https-port=<PORT>
3226 Specify the port number which appears in Location header
3227 field when redirect to HTTPS URI is made due to
3228 "redirect-if-not-tls" parameter in --backend option.
3230 << config->http.redirect_https_port << R"(
3233 --api-max-request-body=<SIZE>
3234 Set the maximum size of request body for API request.
3236 << util::utos_unit(config->api.max_request_body) << R"(
3239 --dns-cache-timeout=<DURATION>
3240 Set duration that cached DNS results remain valid. Note
3241 that nghttpx caches the unsuccessful results as well.
3243 << util::duration_str(config->dns.timeout.cache) << R"(
3244 --dns-lookup-timeout=<DURATION>
3245 Set timeout that DNS server is given to respond to the
3246 initial DNS query. For the 2nd and later queries,
3247 server is given time based on this timeout, and it is
3250 << util::duration_str(config->dns.timeout.lookup) << R"(
3252 Set the number of DNS query before nghttpx gives up name
3255 << config->dns.max_try << R"(
3256 --frontend-max-requests=<N>
3257 The number of requests that single frontend connection
3258 can process. For HTTP/2, this is the number of streams
3259 in one HTTP/2 connection. For HTTP/1, this is the
3260 number of keep alive requests. This is hint to nghttpx,
3261 and it may allow additional few requests. The default
3265 --frontend-http2-dump-request-header=<PATH>
3266 Dumps request headers received by HTTP/2 frontend to the
3267 file denoted in <PATH>. The output is done in HTTP/1
3268 header field format and each header block is followed by
3269 an empty line. This option is not thread safe and MUST
3270 NOT be used with option -n<N>, where <N> >= 2.
3271 --frontend-http2-dump-response-header=<PATH>
3272 Dumps response headers sent from HTTP/2 frontend to the
3273 file denoted in <PATH>. The output is done in HTTP/1
3274 header field format and each header block is followed by
3275 an empty line. This option is not thread safe and MUST
3276 NOT be used with option -n<N>, where <N> >= 2.
3277 -o, --frontend-frame-debug
3278 Print HTTP/2 frames in frontend to stderr. This option
3279 is not thread safe and MUST NOT be used with option
3284 Run in a background. If -D is used, the current working
3285 directory is changed to '/'.
3287 Set path to save PID of this program.
3289 Run this program as <USER>. This option is intended to
3290 be used to drop root privileges.
3292 Run this program in a single process mode for debugging
3293 purpose. Without this option, nghttpx creates at least
3294 2 processes: main and worker processes. If this option
3295 is used, main and worker are unified into a single
3296 process. nghttpx still spawns additional process if
3297 neverbleed is used. In the single process mode, the
3298 signal handling feature is disabled.
3299 --max-worker-processes=<N>
3300 The maximum number of worker processes. nghttpx spawns
3301 new worker process when it reloads its configuration.
3302 The previous worker process enters graceful termination
3303 period and will terminate when it finishes handling the
3304 existing connections. However, if reloading
3305 configurations happen very frequently, the worker
3306 processes might be piled up if they take a bit long time
3307 to finish the existing connections. With this option,
3308 if the number of worker processes exceeds the given
3309 value, the oldest worker process is terminated
3310 immediately. Specifying 0 means no limit and it is the
3312 --worker-process-grace-shutdown-period=<DURATION>
3313 Maximum period for a worker process to terminate
3314 gracefully. When a worker process enters in graceful
3315 shutdown period (e.g., when nghttpx reloads its
3316 configuration) and it does not finish handling the
3317 existing connections in the given period of time, it is
3318 immediately terminated. Specifying 0 means no limit and
3319 it is the default behaviour.
3323 Set mruby script file
3324 --ignore-per-pattern-mruby-error
3325 Ignore mruby compile error for per-pattern mruby script
3326 file. If error occurred, it is treated as if no mruby
3327 file were specified for the pattern.
3333 --frontend-quic-idle-timeout=<DURATION>
3334 Specify an idle timeout for QUIC connection.
3336 << util::duration_str(config->quic.upstream.timeout.idle) << R"(
3337 --frontend-quic-debug-log
3338 Output QUIC debug log to /dev/stderr.
3339 --quic-bpf-program-file=<PATH>
3340 Specify a path to eBPF program file reuseport_kern.o to
3341 direct an incoming QUIC UDP datagram to a correct
3344 << config->quic.bpf.prog_file << R"(
3345 --frontend-quic-early-data
3346 Enable early data on frontend QUIC connections. nghttpx
3347 sends "Early-Data" header field to a backend server if a
3348 request is received in early data and handshake has not
3349 finished. All backend servers should deal with possibly
3351 --frontend-quic-qlog-dir=<DIR>
3352 Specify a directory where a qlog file is written for
3353 frontend QUIC connections. A qlog file is created per
3354 each QUIC connection. The file name is ISO8601 basic
3355 format, followed by "-", server Source Connection ID and
3357 --frontend-quic-require-token
3358 Require an address validation token for a frontend QUIC
3359 connection. Server sends a token in Retry packet or
3360 NEW_TOKEN frame in the previous connection.
3361 --frontend-quic-congestion-controller=<CC>
3362 Specify a congestion controller algorithm for a frontend
3363 QUIC connection. <CC> should be either "cubic" or
3366 << (config->quic.upstream.congestion_controller == NGTCP2_CC_ALGO_CUBIC
3370 --frontend-quic-secret-file=<PATH>
3371 Path to file that contains secure random data to be used
3372 as QUIC keying materials. It is used to derive keys for
3373 encrypting tokens and Connection IDs. It is not used to
3374 encrypt QUIC packets. Each line of this file must
3375 contain exactly 136 bytes hex-encoded string (when
3376 decoded the byte string is 68 bytes long). The first 2
3377 bits of decoded byte string are used to identify the
3378 keying material. An empty line or a line which starts
3379 '#' is ignored. The file can contain more than one
3380 keying materials. Because the identifier is 2 bits, at
3381 most 4 keying materials are read and the remaining data
3382 is discarded. The first keying material in the file is
3383 primarily used for encryption and decryption for new
3384 connection. The other ones are used to decrypt data for
3385 the existing connections. Specifying multiple keying
3386 materials enables key rotation. Please note that key
3387 rotation does not occur automatically. User should
3388 update files or change options values and restart
3389 nghttpx gracefully. If opening or reading given file
3390 fails, all loaded keying materials are discarded and it
3391 is treated as if none of this option is given. If this
3392 option is not given or an error occurred while opening
3393 or reading a file, a keying material is generated
3394 internally on startup and reload.
3395 --quic-server-id=<HEXSTRING>
3396 Specify server ID encoded in Connection ID to identify
3397 this particular server instance. Connection ID is
3398 encrypted and this part is not visible in public. It
3399 must be 4 bytes long and must be encoded in hex string
3400 (which is 8 bytes long). If this option is omitted, a
3401 random server ID is generated on startup and
3402 configuration reload.
3403 --frontend-quic-initial-rtt=<DURATION>
3404 Specify the initial RTT of the frontend QUIC connection.
3406 << util::duration_str(config->quic.upstream.initial_rtt) << R"(
3409 --frontend-http3-window-size=<SIZE>
3410 Sets the per-stream initial window size of HTTP/3
3411 frontend connection.
3413 << util::utos_unit(config->http3.upstream.window_size) << R"(
3414 --frontend-http3-connection-window-size=<SIZE>
3415 Sets the per-connection window size of HTTP/3 frontend
3418 << util::utos_unit(config->http3.upstream.connection_window_size) << R"(
3419 --frontend-http3-max-window-size=<SIZE>
3420 Sets the maximum per-stream window size of HTTP/3
3421 frontend connection. The window size is adjusted based
3422 on the receiving rate of stream data. The initial value
3423 is the value specified by --frontend-http3-window-size
3424 and the window size grows up to <SIZE> bytes.
3426 << util::utos_unit(config->http3.upstream.max_window_size) << R"(
3427 --frontend-http3-max-connection-window-size=<SIZE>
3428 Sets the maximum per-connection window size of HTTP/3
3429 frontend connection. The window size is adjusted based
3430 on the receiving rate of stream data. The initial value
3431 is the value specified by
3432 --frontend-http3-connection-window-size and the window
3433 size grows up to <SIZE> bytes.
3435 << util::utos_unit(config->http3.upstream.max_connection_window_size)
3437 --frontend-http3-max-concurrent-streams=<N>
3438 Set the maximum number of the concurrent streams in one
3439 frontend HTTP/3 connection.
3441 << config->http3.upstream.max_concurrent_streams << R"(
3443 #endif // ENABLE_HTTP3
3448 Load configuration from <PATH>. Please note that
3449 nghttpx always tries to read the default configuration
3450 file if --conf is not given.
3452 << config->conf_path << R"(
3454 Load additional configurations from <PATH>. File <PATH>
3455 is read when configuration parser encountered this
3456 option. This option can be used multiple times, or even
3459 Print version and exit.
3460 -h, --help Print this help and exit.
3464 The <SIZE> argument is an integer and an optional unit (e.g., 10K is
3465 10 * 1024). Units are K, M and G (powers of 1024).
3467 The <DURATION> argument is an integer and an optional unit (e.g., 1s
3468 is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
3469 (hours, minutes, seconds and milliseconds, respectively). If a unit
3470 is omitted, a second is used as unit.)"
3476 int process_options(Config *config,
3477 std::vector<std::pair<StringRef, StringRef>> &cmdcfgs) {
3478 std::array<char, STRERROR_BUFSIZE> errbuf;
3479 std::map<StringRef, size_t> pattern_addr_indexer;
3480 if (conf_exists(config->conf_path.c_str())) {
3481 LOG(NOTICE) << "Loading configuration from " << config->conf_path;
3482 std::set<StringRef> include_set;
3483 if (load_config(config, config->conf_path.c_str(), include_set,
3484 pattern_addr_indexer) == -1) {
3485 LOG(FATAL) << "Failed to load configuration from " << config->conf_path;
3488 assert(include_set.empty());
3491 // Reopen log files using configurations in file
3492 reopen_log_files(config->logging);
3495 std::set<StringRef> include_set;
3497 for (auto &p : cmdcfgs) {
3498 if (parse_config(config, p.first, p.second, include_set,
3499 pattern_addr_indexer) == -1) {
3500 LOG(FATAL) << "Failed to parse command-line argument.";
3505 assert(include_set.empty());
3508 Log::set_severity_level(config->logging.severity);
3510 auto &loggingconf = config->logging;
3512 if (loggingconf.access.syslog || loggingconf.error.syslog) {
3513 openlog("nghttpx", LOG_NDELAY | LOG_NOWAIT | LOG_PID,
3514 loggingconf.syslog_facility);
3517 if (reopen_log_files(config->logging) != 0) {
3518 LOG(FATAL) << "Failed to open log file";
3522 redirect_stderr_to_errorlog(loggingconf);
3524 if (config->uid != 0) {
3525 if (log_config()->accesslog_fd != -1 &&
3526 fchown(log_config()->accesslog_fd, config->uid, config->gid) == -1) {
3528 LOG(WARN) << "Changing owner of access log file failed: "
3529 << xsi_strerror(error, errbuf.data(), errbuf.size());
3531 if (log_config()->errorlog_fd != -1 &&
3532 fchown(log_config()->errorlog_fd, config->uid, config->gid) == -1) {
3534 LOG(WARN) << "Changing owner of error log file failed: "
3535 << xsi_strerror(error, errbuf.data(), errbuf.size());
3539 if (config->single_thread) {
3540 LOG(WARN) << "single-thread: Set workers to 1";
3541 config->num_worker = 1;
3544 auto &http2conf = config->http2;
3546 auto &dumpconf = http2conf.upstream.debug.dump;
3548 if (!dumpconf.request_header_file.empty()) {
3549 auto path = dumpconf.request_header_file.c_str();
3550 auto f = open_file_for_write(path);
3553 LOG(FATAL) << "Failed to open http2 upstream request header file: "
3558 dumpconf.request_header = f;
3560 if (config->uid != 0) {
3561 if (chown(path, config->uid, config->gid) == -1) {
3563 LOG(WARN) << "Changing owner of http2 upstream request header file "
3564 << path << " failed: "
3565 << xsi_strerror(error, errbuf.data(), errbuf.size());
3570 if (!dumpconf.response_header_file.empty()) {
3571 auto path = dumpconf.response_header_file.c_str();
3572 auto f = open_file_for_write(path);
3575 LOG(FATAL) << "Failed to open http2 upstream response header file: "
3580 dumpconf.response_header = f;
3582 if (config->uid != 0) {
3583 if (chown(path, config->uid, config->gid) == -1) {
3585 LOG(WARN) << "Changing owner of http2 upstream response header file"
3586 << " " << path << " failed: "
3587 << xsi_strerror(error, errbuf.data(), errbuf.size());
3593 auto &tlsconf = config->tls;
3595 if (tlsconf.npn_list.empty()) {
3596 tlsconf.npn_list = util::split_str(DEFAULT_NPN_LIST, ',');
3599 if (!tlsconf.tls_proto_list.empty()) {
3600 tlsconf.tls_proto_mask = tls::create_tls_proto_mask(tlsconf.tls_proto_list);
3603 // TODO We depends on the ordering of protocol version macro in
3605 if (tlsconf.min_proto_version > tlsconf.max_proto_version) {
3606 LOG(ERROR) << "tls-max-proto-version must be equal to or larger than "
3607 "tls-min-proto-version";
3611 if (tls::set_alpn_prefs(tlsconf.alpn_prefs, tlsconf.npn_list) != 0) {
3615 tlsconf.bio_method = create_bio_method();
3617 auto &listenerconf = config->conn.listener;
3618 auto &upstreamconf = config->conn.upstream;
3620 if (listenerconf.addrs.empty()) {
3621 UpstreamAddr addr{};
3622 addr.host = StringRef::from_lit("*");
3625 addr.family = AF_INET;
3627 listenerconf.addrs.push_back(addr);
3628 addr.family = AF_INET6;
3630 listenerconf.addrs.push_back(std::move(addr));
3633 if (upstreamconf.worker_connections == 0) {
3634 upstreamconf.worker_connections = std::numeric_limits<size_t>::max();
3637 if (tls::upstream_tls_enabled(config->conn) &&
3638 (tlsconf.private_key_file.empty() || tlsconf.cert_file.empty())) {
3639 LOG(FATAL) << "TLS private key and certificate files are required. "
3640 "Specify them in command-line, or in configuration file "
3641 "using private-key-file and certificate-file options.";
3645 if (tls::upstream_tls_enabled(config->conn) && !tlsconf.ocsp.disabled) {
3647 if (stat(tlsconf.ocsp.fetch_ocsp_response_file.c_str(), &buf) != 0) {
3648 tlsconf.ocsp.disabled = true;
3649 LOG(WARN) << "--fetch-ocsp-response-file: "
3650 << tlsconf.ocsp.fetch_ocsp_response_file
3651 << " not found. OCSP stapling has been disabled.";
3655 if (configure_downstream_group(config, config->http2_proxy, false, tlsconf) !=
3660 std::array<char, util::max_hostport> hostport_buf;
3662 auto &proxy = config->downstream_http_proxy;
3663 if (!proxy.host.empty()) {
3664 auto hostport = util::make_hostport(std::begin(hostport_buf),
3665 StringRef{proxy.host}, proxy.port);
3666 if (resolve_hostname(&proxy.addr, proxy.host.c_str(), proxy.port,
3668 LOG(FATAL) << "Resolving backend HTTP proxy address failed: " << hostport;
3671 LOG(NOTICE) << "Backend HTTP proxy address: " << hostport << " -> "
3672 << util::to_numeric_addr(&proxy.addr);
3676 auto &memcachedconf = tlsconf.session_cache.memcached;
3677 if (!memcachedconf.host.empty()) {
3678 auto hostport = util::make_hostport(std::begin(hostport_buf),
3679 StringRef{memcachedconf.host},
3680 memcachedconf.port);
3681 if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.c_str(),
3682 memcachedconf.port, memcachedconf.family) == -1) {
3684 << "Resolving memcached address for TLS session cache failed: "
3688 LOG(NOTICE) << "Memcached address for TLS session cache: " << hostport
3689 << " -> " << util::to_numeric_addr(&memcachedconf.addr);
3690 if (memcachedconf.tls) {
3691 LOG(NOTICE) << "Connection to memcached for TLS session cache will be "
3698 auto &memcachedconf = tlsconf.ticket.memcached;
3699 if (!memcachedconf.host.empty()) {
3700 auto hostport = util::make_hostport(std::begin(hostport_buf),
3701 StringRef{memcachedconf.host},
3702 memcachedconf.port);
3703 if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.c_str(),
3704 memcachedconf.port, memcachedconf.family) == -1) {
3705 LOG(FATAL) << "Resolving memcached address for TLS ticket key failed: "
3709 LOG(NOTICE) << "Memcached address for TLS ticket key: " << hostport
3710 << " -> " << util::to_numeric_addr(&memcachedconf.addr);
3711 if (memcachedconf.tls) {
3712 LOG(NOTICE) << "Connection to memcached for TLS ticket key will be "
3718 if (config->rlimit_nofile) {
3719 struct rlimit lim = {static_cast<rlim_t>(config->rlimit_nofile),
3720 static_cast<rlim_t>(config->rlimit_nofile)};
3721 if (setrlimit(RLIMIT_NOFILE, &lim) != 0) {
3723 LOG(WARN) << "Setting rlimit-nofile failed: "
3724 << xsi_strerror(error, errbuf.data(), errbuf.size());
3728 if (config->rlimit_memlock) {
3729 struct rlimit lim = {static_cast<rlim_t>(config->rlimit_memlock),
3730 static_cast<rlim_t>(config->rlimit_memlock)};
3731 if (setrlimit(RLIMIT_MEMLOCK, &lim) != 0) {
3733 LOG(WARN) << "Setting rlimit-memlock failed: "
3734 << xsi_strerror(error, errbuf.data(), errbuf.size());
3738 auto &fwdconf = config->http.forwarded;
3740 if (fwdconf.by_node_type == ForwardedNode::OBFUSCATED &&
3741 fwdconf.by_obfuscated.empty()) {
3742 // 2 for '_' and terminal NULL
3743 auto iov = make_byte_ref(config->balloc, SHRPX_OBFUSCATED_NODE_LENGTH + 2);
3746 auto gen = util::make_mt19937();
3747 p = util::random_alpha_digit(p, p + SHRPX_OBFUSCATED_NODE_LENGTH, gen);
3749 fwdconf.by_obfuscated = StringRef{iov.base, p};
3752 if (config->http2.upstream.debug.frame_debug) {
3753 // To make it sync to logging
3755 if (isatty(fileno(stdout))) {
3756 set_color_output(true);
3761 config->http2.upstream.callbacks = create_http2_upstream_callbacks();
3762 config->http2.downstream.callbacks = create_http2_downstream_callbacks();
3764 if (!config->http.altsvcs.empty()) {
3765 config->http.altsvc_header_value =
3766 http::create_altsvc_header_value(config->balloc, config->http.altsvcs);
3769 if (!config->http.http2_altsvcs.empty()) {
3770 config->http.http2_altsvc_header_value = http::create_altsvc_header_value(
3771 config->balloc, config->http.http2_altsvcs);
3779 // Closes file descriptor which are opened for listeners in config,
3780 // and are not inherited from |iaddrs|.
3781 void close_not_inherited_fd(Config *config,
3782 const std::vector<InheritedAddr> &iaddrs) {
3783 auto &listenerconf = config->conn.listener;
3785 for (auto &addr : listenerconf.addrs) {
3786 auto inherited = std::find_if(
3787 std::begin(iaddrs), std::end(iaddrs),
3788 [&addr](const InheritedAddr &iaddr) { return addr.fd == iaddr.fd; });
3790 if (inherited != std::end(iaddrs)) {
3800 void reload_config(WorkerProcess *wp) {
3803 LOG(NOTICE) << "Reloading configuration";
3805 auto cur_config = mod_config();
3806 auto new_config = std::make_unique<Config>();
3808 fill_default_config(new_config.get());
3810 new_config->conf_path =
3811 make_string_ref(new_config->balloc, cur_config->conf_path);
3812 // daemon option is ignored here.
3813 new_config->daemon = cur_config->daemon;
3814 // loop is reused, and ev_loop_flags gets ignored
3815 new_config->ev_loop_flags = cur_config->ev_loop_flags;
3816 new_config->config_revision = cur_config->config_revision + 1;
3818 rv = process_options(new_config.get(), suconfig.cmdcfgs);
3820 LOG(ERROR) << "Failed to process new configuration";
3824 auto iaddrs = get_inherited_addr_from_config(new_config->balloc, cur_config);
3826 if (create_acceptor_socket(new_config.get(), iaddrs) != 0) {
3827 close_not_inherited_fd(new_config.get(), iaddrs);
3831 // According to libev documentation, flags are ignored since we have
3832 // already created first default loop.
3833 auto loop = ev_default_loop(new_config->ev_loop_flags);
3837 int quic_ipc_fd = 0;
3839 auto quic_lwps = collect_quic_lingering_worker_processes();
3841 std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> cid_prefixes;
3843 if (generate_cid_prefix(cid_prefixes, new_config.get()) != 0) {
3844 close_not_inherited_fd(new_config.get(), iaddrs);
3847 #endif // ENABLE_HTTP3
3849 // fork_worker_process and forked child process assumes new
3850 // configuration can be obtained from get_config().
3852 auto old_config = replace_config(std::move(new_config));
3854 auto pid = fork_worker_process(ipc_fd
3858 #endif // ENABLE_HTTP3
3864 cid_prefixes, quic_lwps
3865 #endif // ENABLE_HTTP3
3869 LOG(ERROR) << "Failed to process new configuration";
3871 new_config = replace_config(std::move(old_config));
3872 close_not_inherited_fd(new_config.get(), iaddrs);
3877 close_unused_inherited_addr(iaddrs);
3879 // Send last worker process a graceful shutdown notice
3880 auto &last_wp = worker_processes.back();
3881 ipc_send(last_wp.get(), SHRPX_IPC_GRACEFUL_SHUTDOWN);
3882 worker_process_set_termination_deadline(last_wp.get(), loop);
3883 // We no longer use signals for this worker.
3884 last_wp->shutdown_signal_watchers();
3886 worker_process_add(std::make_unique<WorkerProcess>(loop, pid, ipc_fd
3889 quic_ipc_fd, cid_prefixes
3890 #endif // ENABLE_HTTP3
3893 worker_process_adjust_limit();
3895 if (!get_config()->pid_file.empty()) {
3901 int main(int argc, char **argv) {
3903 std::array<char, STRERROR_BUFSIZE> errbuf;
3905 nghttp2::tls::libssl_init();
3908 nghttp2::tls::LibsslGlobalLock lock;
3911 Log::set_severity_level(NOTICE);
3913 fill_default_config(mod_config());
3915 // make copy of stderr
3916 store_original_fds();
3918 // First open log files with default configuration, so that we can
3919 // log errors/warnings while reading configuration files.
3920 reopen_log_files(get_config()->logging);
3922 suconfig.original_argv = argv;
3924 // We have to copy argv, since getopt_long may change its content.
3925 suconfig.argc = argc;
3926 suconfig.argv = new char *[argc];
3928 for (int i = 0; i < argc; ++i) {
3929 suconfig.argv[i] = strdup(argv[i]);
3930 if (suconfig.argv[i] == nullptr) {
3932 LOG(FATAL) << "failed to copy argv: "
3933 << xsi_strerror(error, errbuf.data(), errbuf.size());
3938 suconfig.cwd = getcwd(nullptr, 0);
3939 if (suconfig.cwd == nullptr) {
3941 LOG(FATAL) << "failed to get current working directory: errno=" << error;
3945 auto &cmdcfgs = suconfig.cmdcfgs;
3948 static int flag = 0;
3949 static constexpr option long_options[] = {
3950 {SHRPX_OPT_DAEMON.c_str(), no_argument, nullptr, 'D'},
3951 {SHRPX_OPT_LOG_LEVEL.c_str(), required_argument, nullptr, 'L'},
3952 {SHRPX_OPT_BACKEND.c_str(), required_argument, nullptr, 'b'},
3953 {SHRPX_OPT_HTTP2_MAX_CONCURRENT_STREAMS.c_str(), required_argument,
3955 {SHRPX_OPT_FRONTEND.c_str(), required_argument, nullptr, 'f'},
3956 {"help", no_argument, nullptr, 'h'},
3957 {SHRPX_OPT_INSECURE.c_str(), no_argument, nullptr, 'k'},
3958 {SHRPX_OPT_WORKERS.c_str(), required_argument, nullptr, 'n'},
3959 {SHRPX_OPT_CLIENT_PROXY.c_str(), no_argument, nullptr, 'p'},
3960 {SHRPX_OPT_HTTP2_PROXY.c_str(), no_argument, nullptr, 's'},
3961 {"version", no_argument, nullptr, 'v'},
3962 {SHRPX_OPT_FRONTEND_FRAME_DEBUG.c_str(), no_argument, nullptr, 'o'},
3963 {SHRPX_OPT_ADD_X_FORWARDED_FOR.c_str(), no_argument, &flag, 1},
3964 {SHRPX_OPT_FRONTEND_HTTP2_READ_TIMEOUT.c_str(), required_argument,
3966 {SHRPX_OPT_FRONTEND_READ_TIMEOUT.c_str(), required_argument, &flag, 3},
3967 {SHRPX_OPT_FRONTEND_WRITE_TIMEOUT.c_str(), required_argument, &flag, 4},
3968 {SHRPX_OPT_BACKEND_READ_TIMEOUT.c_str(), required_argument, &flag, 5},
3969 {SHRPX_OPT_BACKEND_WRITE_TIMEOUT.c_str(), required_argument, &flag, 6},
3970 {SHRPX_OPT_ACCESSLOG_FILE.c_str(), required_argument, &flag, 7},
3971 {SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT.c_str(), required_argument, &flag,
3973 {SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS.c_str(), required_argument, &flag,
3975 {SHRPX_OPT_PID_FILE.c_str(), required_argument, &flag, 10},
3976 {SHRPX_OPT_USER.c_str(), required_argument, &flag, 11},
3977 {"conf", required_argument, &flag, 12},
3978 {SHRPX_OPT_SYSLOG_FACILITY.c_str(), required_argument, &flag, 14},
3979 {SHRPX_OPT_BACKLOG.c_str(), required_argument, &flag, 15},
3980 {SHRPX_OPT_CIPHERS.c_str(), required_argument, &flag, 16},
3981 {SHRPX_OPT_CLIENT.c_str(), no_argument, &flag, 17},
3982 {SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS.c_str(), required_argument, &flag,
3984 {SHRPX_OPT_CACERT.c_str(), required_argument, &flag, 19},
3985 {SHRPX_OPT_BACKEND_IPV4.c_str(), no_argument, &flag, 20},
3986 {SHRPX_OPT_BACKEND_IPV6.c_str(), no_argument, &flag, 21},
3987 {SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE.c_str(), required_argument, &flag,
3989 {SHRPX_OPT_NO_VIA.c_str(), no_argument, &flag, 23},
3990 {SHRPX_OPT_SUBCERT.c_str(), required_argument, &flag, 24},
3991 {SHRPX_OPT_HTTP2_BRIDGE.c_str(), no_argument, &flag, 25},
3992 {SHRPX_OPT_BACKEND_HTTP_PROXY_URI.c_str(), required_argument, &flag,
3994 {SHRPX_OPT_BACKEND_NO_TLS.c_str(), no_argument, &flag, 27},
3995 {SHRPX_OPT_OCSP_STARTUP.c_str(), no_argument, &flag, 28},
3996 {SHRPX_OPT_FRONTEND_NO_TLS.c_str(), no_argument, &flag, 29},
3997 {SHRPX_OPT_NO_VERIFY_OCSP.c_str(), no_argument, &flag, 30},
3998 {SHRPX_OPT_BACKEND_TLS_SNI_FIELD.c_str(), required_argument, &flag, 31},
3999 {SHRPX_OPT_DH_PARAM_FILE.c_str(), required_argument, &flag, 33},
4000 {SHRPX_OPT_READ_RATE.c_str(), required_argument, &flag, 34},
4001 {SHRPX_OPT_READ_BURST.c_str(), required_argument, &flag, 35},
4002 {SHRPX_OPT_WRITE_RATE.c_str(), required_argument, &flag, 36},
4003 {SHRPX_OPT_WRITE_BURST.c_str(), required_argument, &flag, 37},
4004 {SHRPX_OPT_NPN_LIST.c_str(), required_argument, &flag, 38},
4005 {SHRPX_OPT_VERIFY_CLIENT.c_str(), no_argument, &flag, 39},
4006 {SHRPX_OPT_VERIFY_CLIENT_CACERT.c_str(), required_argument, &flag, 40},
4007 {SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE.c_str(), required_argument, &flag,
4009 {SHRPX_OPT_CLIENT_CERT_FILE.c_str(), required_argument, &flag, 42},
4010 {SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER.c_str(),
4011 required_argument, &flag, 43},
4012 {SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER.c_str(),
4013 required_argument, &flag, 44},
4014 {SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING.c_str(), no_argument, &flag, 45},
4015 {SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS.c_str(),
4016 required_argument, &flag, 46},
4017 {SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS.c_str(),
4018 required_argument, &flag, 47},
4019 {SHRPX_OPT_TLS_PROTO_LIST.c_str(), required_argument, &flag, 48},
4020 {SHRPX_OPT_PADDING.c_str(), required_argument, &flag, 49},
4021 {SHRPX_OPT_WORKER_READ_RATE.c_str(), required_argument, &flag, 50},
4022 {SHRPX_OPT_WORKER_READ_BURST.c_str(), required_argument, &flag, 51},
4023 {SHRPX_OPT_WORKER_WRITE_RATE.c_str(), required_argument, &flag, 52},
4024 {SHRPX_OPT_WORKER_WRITE_BURST.c_str(), required_argument, &flag, 53},
4025 {SHRPX_OPT_ALTSVC.c_str(), required_argument, &flag, 54},
4026 {SHRPX_OPT_ADD_RESPONSE_HEADER.c_str(), required_argument, &flag, 55},
4027 {SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS.c_str(), required_argument,
4029 {SHRPX_OPT_ACCESSLOG_SYSLOG.c_str(), no_argument, &flag, 57},
4030 {SHRPX_OPT_ERRORLOG_FILE.c_str(), required_argument, &flag, 58},
4031 {SHRPX_OPT_ERRORLOG_SYSLOG.c_str(), no_argument, &flag, 59},
4032 {SHRPX_OPT_STREAM_READ_TIMEOUT.c_str(), required_argument, &flag, 60},
4033 {SHRPX_OPT_STREAM_WRITE_TIMEOUT.c_str(), required_argument, &flag, 61},
4034 {SHRPX_OPT_NO_LOCATION_REWRITE.c_str(), no_argument, &flag, 62},
4035 {SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST.c_str(),
4036 required_argument, &flag, 63},
4037 {SHRPX_OPT_LISTENER_DISABLE_TIMEOUT.c_str(), required_argument, &flag,
4039 {SHRPX_OPT_STRIP_INCOMING_X_FORWARDED_FOR.c_str(), no_argument, &flag,
4041 {SHRPX_OPT_ACCESSLOG_FORMAT.c_str(), required_argument, &flag, 66},
4042 {SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND.c_str(),
4043 required_argument, &flag, 67},
4044 {SHRPX_OPT_TLS_TICKET_KEY_FILE.c_str(), required_argument, &flag, 68},
4045 {SHRPX_OPT_RLIMIT_NOFILE.c_str(), required_argument, &flag, 69},
4046 {SHRPX_OPT_BACKEND_RESPONSE_BUFFER.c_str(), required_argument, &flag,
4048 {SHRPX_OPT_BACKEND_REQUEST_BUFFER.c_str(), required_argument, &flag,
4050 {SHRPX_OPT_NO_HOST_REWRITE.c_str(), no_argument, &flag, 73},
4051 {SHRPX_OPT_NO_SERVER_PUSH.c_str(), no_argument, &flag, 74},
4052 {SHRPX_OPT_BACKEND_HTTP2_CONNECTIONS_PER_WORKER.c_str(),
4053 required_argument, &flag, 76},
4054 {SHRPX_OPT_FETCH_OCSP_RESPONSE_FILE.c_str(), required_argument, &flag,
4056 {SHRPX_OPT_OCSP_UPDATE_INTERVAL.c_str(), required_argument, &flag, 78},
4057 {SHRPX_OPT_NO_OCSP.c_str(), no_argument, &flag, 79},
4058 {SHRPX_OPT_HEADER_FIELD_BUFFER.c_str(), required_argument, &flag, 80},
4059 {SHRPX_OPT_MAX_HEADER_FIELDS.c_str(), required_argument, &flag, 81},
4060 {SHRPX_OPT_ADD_REQUEST_HEADER.c_str(), required_argument, &flag, 82},
4061 {SHRPX_OPT_INCLUDE.c_str(), required_argument, &flag, 83},
4062 {SHRPX_OPT_TLS_TICKET_KEY_CIPHER.c_str(), required_argument, &flag, 84},
4063 {SHRPX_OPT_HOST_REWRITE.c_str(), no_argument, &flag, 85},
4064 {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED.c_str(), required_argument,
4066 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED.c_str(), required_argument, &flag,
4068 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_INTERVAL.c_str(), required_argument,
4070 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_RETRY.c_str(),
4071 required_argument, &flag, 89},
4072 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_FAIL.c_str(), required_argument,
4074 {SHRPX_OPT_MRUBY_FILE.c_str(), required_argument, &flag, 91},
4075 {SHRPX_OPT_ACCEPT_PROXY_PROTOCOL.c_str(), no_argument, &flag, 93},
4076 {SHRPX_OPT_FASTOPEN.c_str(), required_argument, &flag, 94},
4077 {SHRPX_OPT_TLS_DYN_REC_WARMUP_THRESHOLD.c_str(), required_argument,
4079 {SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT.c_str(), required_argument, &flag,
4081 {SHRPX_OPT_ADD_FORWARDED.c_str(), required_argument, &flag, 97},
4082 {SHRPX_OPT_STRIP_INCOMING_FORWARDED.c_str(), no_argument, &flag, 98},
4083 {SHRPX_OPT_FORWARDED_BY.c_str(), required_argument, &flag, 99},
4084 {SHRPX_OPT_FORWARDED_FOR.c_str(), required_argument, &flag, 100},
4085 {SHRPX_OPT_RESPONSE_HEADER_FIELD_BUFFER.c_str(), required_argument,
4087 {SHRPX_OPT_MAX_RESPONSE_HEADER_FIELDS.c_str(), required_argument, &flag,
4089 {SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST.c_str(), no_argument, &flag, 103},
4090 {SHRPX_OPT_REQUEST_HEADER_FIELD_BUFFER.c_str(), required_argument,
4092 {SHRPX_OPT_MAX_REQUEST_HEADER_FIELDS.c_str(), required_argument, &flag,
4094 {SHRPX_OPT_BACKEND_HTTP1_TLS.c_str(), no_argument, &flag, 106},
4095 {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS.c_str(), no_argument, &flag,
4097 {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE.c_str(),
4098 required_argument, &flag, 109},
4099 {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE.c_str(),
4100 required_argument, &flag, 110},
4101 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS.c_str(), no_argument, &flag,
4103 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE.c_str(),
4104 required_argument, &flag, 112},
4105 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE.c_str(),
4106 required_argument, &flag, 113},
4107 {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY.c_str(),
4108 required_argument, &flag, 114},
4109 {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY.c_str(),
4110 required_argument, &flag, 115},
4111 {SHRPX_OPT_BACKEND_ADDRESS_FAMILY.c_str(), required_argument, &flag,
4113 {SHRPX_OPT_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS.c_str(),
4114 required_argument, &flag, 117},
4115 {SHRPX_OPT_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS.c_str(),
4116 required_argument, &flag, 118},
4117 {SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND.c_str(), required_argument,
4119 {SHRPX_OPT_BACKEND_TLS.c_str(), no_argument, &flag, 120},
4120 {SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST.c_str(), required_argument,
4122 {SHRPX_OPT_ERROR_PAGE.c_str(), required_argument, &flag, 122},
4123 {SHRPX_OPT_NO_KQUEUE.c_str(), no_argument, &flag, 123},
4124 {SHRPX_OPT_FRONTEND_HTTP2_SETTINGS_TIMEOUT.c_str(), required_argument,
4126 {SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT.c_str(), required_argument,
4128 {SHRPX_OPT_API_MAX_REQUEST_BODY.c_str(), required_argument, &flag, 126},
4129 {SHRPX_OPT_BACKEND_MAX_BACKOFF.c_str(), required_argument, &flag, 127},
4130 {SHRPX_OPT_SERVER_NAME.c_str(), required_argument, &flag, 128},
4131 {SHRPX_OPT_NO_SERVER_REWRITE.c_str(), no_argument, &flag, 129},
4132 {SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE.c_str(),
4133 no_argument, &flag, 130},
4134 {SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE.c_str(), no_argument,
4136 {SHRPX_OPT_FRONTEND_HTTP2_WINDOW_SIZE.c_str(), required_argument, &flag,
4138 {SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_SIZE.c_str(),
4139 required_argument, &flag, 133},
4140 {SHRPX_OPT_BACKEND_HTTP2_WINDOW_SIZE.c_str(), required_argument, &flag,
4142 {SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE.c_str(),
4143 required_argument, &flag, 135},
4144 {SHRPX_OPT_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE.c_str(),
4145 required_argument, &flag, 136},
4146 {SHRPX_OPT_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE.c_str(),
4147 required_argument, &flag, 137},
4148 {SHRPX_OPT_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE.c_str(),
4149 required_argument, &flag, 138},
4150 {SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE.c_str(),
4151 required_argument, &flag, 139},
4152 {SHRPX_OPT_ECDH_CURVES.c_str(), required_argument, &flag, 140},
4153 {SHRPX_OPT_TLS_SCT_DIR.c_str(), required_argument, &flag, 141},
4154 {SHRPX_OPT_BACKEND_CONNECT_TIMEOUT.c_str(), required_argument, &flag,
4156 {SHRPX_OPT_DNS_CACHE_TIMEOUT.c_str(), required_argument, &flag, 143},
4157 {SHRPX_OPT_DNS_LOOKUP_TIMEOUT.c_str(), required_argument, &flag, 144},
4158 {SHRPX_OPT_DNS_MAX_TRY.c_str(), required_argument, &flag, 145},
4159 {SHRPX_OPT_FRONTEND_KEEP_ALIVE_TIMEOUT.c_str(), required_argument,
4161 {SHRPX_OPT_PSK_SECRETS.c_str(), required_argument, &flag, 147},
4162 {SHRPX_OPT_CLIENT_PSK_SECRETS.c_str(), required_argument, &flag, 148},
4163 {SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST.c_str(), no_argument,
4165 {SHRPX_OPT_CLIENT_CIPHERS.c_str(), required_argument, &flag, 150},
4166 {SHRPX_OPT_ACCESSLOG_WRITE_EARLY.c_str(), no_argument, &flag, 151},
4167 {SHRPX_OPT_TLS_MIN_PROTO_VERSION.c_str(), required_argument, &flag,
4169 {SHRPX_OPT_TLS_MAX_PROTO_VERSION.c_str(), required_argument, &flag,
4171 {SHRPX_OPT_REDIRECT_HTTPS_PORT.c_str(), required_argument, &flag, 154},
4172 {SHRPX_OPT_FRONTEND_MAX_REQUESTS.c_str(), required_argument, &flag,
4174 {SHRPX_OPT_SINGLE_THREAD.c_str(), no_argument, &flag, 156},
4175 {SHRPX_OPT_NO_ADD_X_FORWARDED_PROTO.c_str(), no_argument, &flag, 157},
4176 {SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO.c_str(), no_argument,
4178 {SHRPX_OPT_SINGLE_PROCESS.c_str(), no_argument, &flag, 159},
4179 {SHRPX_OPT_VERIFY_CLIENT_TOLERATE_EXPIRED.c_str(), no_argument, &flag,
4181 {SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR.c_str(), no_argument, &flag,
4183 {SHRPX_OPT_TLS_NO_POSTPONE_EARLY_DATA.c_str(), no_argument, &flag, 162},
4184 {SHRPX_OPT_TLS_MAX_EARLY_DATA.c_str(), required_argument, &flag, 163},
4185 {SHRPX_OPT_TLS13_CIPHERS.c_str(), required_argument, &flag, 164},
4186 {SHRPX_OPT_TLS13_CLIENT_CIPHERS.c_str(), required_argument, &flag, 165},
4187 {SHRPX_OPT_NO_STRIP_INCOMING_EARLY_DATA.c_str(), no_argument, &flag,
4189 {SHRPX_OPT_NO_HTTP2_CIPHER_BLOCK_LIST.c_str(), no_argument, &flag, 167},
4190 {SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLOCK_LIST.c_str(), no_argument,
4192 {SHRPX_OPT_QUIC_BPF_PROGRAM_FILE.c_str(), required_argument, &flag,
4194 {SHRPX_OPT_NO_QUIC_BPF.c_str(), no_argument, &flag, 170},
4195 {SHRPX_OPT_HTTP2_ALTSVC.c_str(), required_argument, &flag, 171},
4196 {SHRPX_OPT_FRONTEND_HTTP3_READ_TIMEOUT.c_str(), required_argument,
4198 {SHRPX_OPT_FRONTEND_QUIC_IDLE_TIMEOUT.c_str(), required_argument, &flag,
4200 {SHRPX_OPT_FRONTEND_QUIC_DEBUG_LOG.c_str(), no_argument, &flag, 174},
4201 {SHRPX_OPT_FRONTEND_HTTP3_WINDOW_SIZE.c_str(), required_argument, &flag,
4203 {SHRPX_OPT_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE.c_str(),
4204 required_argument, &flag, 176},
4205 {SHRPX_OPT_FRONTEND_HTTP3_MAX_WINDOW_SIZE.c_str(), required_argument,
4207 {SHRPX_OPT_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE.c_str(),
4208 required_argument, &flag, 178},
4209 {SHRPX_OPT_FRONTEND_HTTP3_MAX_CONCURRENT_STREAMS.c_str(),
4210 required_argument, &flag, 179},
4211 {SHRPX_OPT_FRONTEND_QUIC_EARLY_DATA.c_str(), no_argument, &flag, 180},
4212 {SHRPX_OPT_FRONTEND_QUIC_QLOG_DIR.c_str(), required_argument, &flag,
4214 {SHRPX_OPT_FRONTEND_QUIC_REQUIRE_TOKEN.c_str(), no_argument, &flag,
4216 {SHRPX_OPT_FRONTEND_QUIC_CONGESTION_CONTROLLER.c_str(),
4217 required_argument, &flag, 183},
4218 {SHRPX_OPT_QUIC_SERVER_ID.c_str(), required_argument, &flag, 185},
4219 {SHRPX_OPT_FRONTEND_QUIC_SECRET_FILE.c_str(), required_argument, &flag,
4221 {SHRPX_OPT_RLIMIT_MEMLOCK.c_str(), required_argument, &flag, 187},
4222 {SHRPX_OPT_MAX_WORKER_PROCESSES.c_str(), required_argument, &flag, 188},
4223 {SHRPX_OPT_WORKER_PROCESS_GRACE_SHUTDOWN_PERIOD.c_str(),
4224 required_argument, &flag, 189},
4225 {SHRPX_OPT_FRONTEND_QUIC_INITIAL_RTT.c_str(), required_argument, &flag,
4227 {nullptr, 0, nullptr, 0}};
4229 int option_index = 0;
4230 int c = getopt_long(argc, argv, "DL:b:c:f:hkn:opsv", long_options,
4237 cmdcfgs.emplace_back(SHRPX_OPT_DAEMON, StringRef::from_lit("yes"));
4240 cmdcfgs.emplace_back(SHRPX_OPT_LOG_LEVEL, StringRef{optarg});
4243 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND, StringRef{optarg});
4246 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_MAX_CONCURRENT_STREAMS,
4250 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND, StringRef{optarg});
4253 print_help(std::cout);
4256 cmdcfgs.emplace_back(SHRPX_OPT_INSECURE, StringRef::from_lit("yes"));
4259 cmdcfgs.emplace_back(SHRPX_OPT_WORKERS, StringRef{optarg});
4262 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_FRAME_DEBUG,
4263 StringRef::from_lit("yes"));
4266 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PROXY, StringRef::from_lit("yes"));
4269 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_PROXY, StringRef::from_lit("yes"));
4272 print_version(std::cout);
4275 util::show_candidates(argv[optind - 1], long_options);
4280 // --add-x-forwarded-for
4281 cmdcfgs.emplace_back(SHRPX_OPT_ADD_X_FORWARDED_FOR,
4282 StringRef::from_lit("yes"));
4285 // --frontend-http2-read-timeout
4286 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_READ_TIMEOUT,
4290 // --frontend-read-timeout
4291 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_READ_TIMEOUT,
4295 // --frontend-write-timeout
4296 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_WRITE_TIMEOUT,
4300 // --backend-read-timeout
4301 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_READ_TIMEOUT, StringRef{optarg});
4304 // --backend-write-timeout
4305 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_WRITE_TIMEOUT,
4309 cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_FILE, StringRef{optarg});
4312 // --backend-keep-alive-timeout
4313 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT,
4317 // --frontend-http2-window-bits
4318 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS,
4322 cmdcfgs.emplace_back(SHRPX_OPT_PID_FILE, StringRef{optarg});
4325 cmdcfgs.emplace_back(SHRPX_OPT_USER, StringRef{optarg});
4329 mod_config()->conf_path =
4330 make_string_ref(mod_config()->balloc, StringRef{optarg});
4333 // --syslog-facility
4334 cmdcfgs.emplace_back(SHRPX_OPT_SYSLOG_FACILITY, StringRef{optarg});
4338 cmdcfgs.emplace_back(SHRPX_OPT_BACKLOG, StringRef{optarg});
4342 cmdcfgs.emplace_back(SHRPX_OPT_CIPHERS, StringRef{optarg});
4346 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT, StringRef::from_lit("yes"));
4349 // --backend-http2-window-bits
4350 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS,
4355 cmdcfgs.emplace_back(SHRPX_OPT_CACERT, StringRef{optarg});
4359 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_IPV4,
4360 StringRef::from_lit("yes"));
4364 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_IPV6,
4365 StringRef::from_lit("yes"));
4368 // --private-key-passwd-file
4369 cmdcfgs.emplace_back(SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE,
4374 cmdcfgs.emplace_back(SHRPX_OPT_NO_VIA, StringRef::from_lit("yes"));
4378 cmdcfgs.emplace_back(SHRPX_OPT_SUBCERT, StringRef{optarg});
4382 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_BRIDGE,
4383 StringRef::from_lit("yes"));
4386 // --backend-http-proxy-uri
4387 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP_PROXY_URI,
4392 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_NO_TLS,
4393 StringRef::from_lit("yes"));
4397 cmdcfgs.emplace_back(SHRPX_OPT_OCSP_STARTUP,
4398 StringRef::from_lit("yes"));
4401 // --frontend-no-tls
4402 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_NO_TLS,
4403 StringRef::from_lit("yes"));
4407 cmdcfgs.emplace_back(SHRPX_OPT_NO_VERIFY_OCSP,
4408 StringRef::from_lit("yes"));
4411 // --backend-tls-sni-field
4412 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SNI_FIELD,
4417 cmdcfgs.emplace_back(SHRPX_OPT_DH_PARAM_FILE, StringRef{optarg});
4421 cmdcfgs.emplace_back(SHRPX_OPT_READ_RATE, StringRef{optarg});
4425 cmdcfgs.emplace_back(SHRPX_OPT_READ_BURST, StringRef{optarg});
4429 cmdcfgs.emplace_back(SHRPX_OPT_WRITE_RATE, StringRef{optarg});
4433 cmdcfgs.emplace_back(SHRPX_OPT_WRITE_BURST, StringRef{optarg});
4437 cmdcfgs.emplace_back(SHRPX_OPT_NPN_LIST, StringRef{optarg});
4441 cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT,
4442 StringRef::from_lit("yes"));
4445 // --verify-client-cacert
4446 cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT_CACERT, StringRef{optarg});
4449 // --client-private-key-file
4450 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE,
4454 // --client-cert-file
4455 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_CERT_FILE, StringRef{optarg});
4458 // --frontend-http2-dump-request-header
4459 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER,
4463 // --frontend-http2-dump-response-header
4464 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER,
4468 // --http2-no-cookie-crumbling
4469 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING,
4470 StringRef::from_lit("yes"));
4473 // --frontend-http2-connection-window-bits
4474 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS,
4478 // --backend-http2-connection-window-bits
4479 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS,
4484 cmdcfgs.emplace_back(SHRPX_OPT_TLS_PROTO_LIST, StringRef{optarg});
4488 cmdcfgs.emplace_back(SHRPX_OPT_PADDING, StringRef{optarg});
4491 // --worker-read-rate
4492 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_READ_RATE, StringRef{optarg});
4495 // --worker-read-burst
4496 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_READ_BURST, StringRef{optarg});
4499 // --worker-write-rate
4500 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_WRITE_RATE, StringRef{optarg});
4503 // --worker-write-burst
4504 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_WRITE_BURST, StringRef{optarg});
4508 cmdcfgs.emplace_back(SHRPX_OPT_ALTSVC, StringRef{optarg});
4511 // --add-response-header
4512 cmdcfgs.emplace_back(SHRPX_OPT_ADD_RESPONSE_HEADER, StringRef{optarg});
4515 // --worker-frontend-connections
4516 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS,
4520 // --accesslog-syslog
4521 cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_SYSLOG,
4522 StringRef::from_lit("yes"));
4526 cmdcfgs.emplace_back(SHRPX_OPT_ERRORLOG_FILE, StringRef{optarg});
4529 // --errorlog-syslog
4530 cmdcfgs.emplace_back(SHRPX_OPT_ERRORLOG_SYSLOG,
4531 StringRef::from_lit("yes"));
4534 // --stream-read-timeout
4535 cmdcfgs.emplace_back(SHRPX_OPT_STREAM_READ_TIMEOUT, StringRef{optarg});
4538 // --stream-write-timeout
4539 cmdcfgs.emplace_back(SHRPX_OPT_STREAM_WRITE_TIMEOUT, StringRef{optarg});
4542 // --no-location-rewrite
4543 cmdcfgs.emplace_back(SHRPX_OPT_NO_LOCATION_REWRITE,
4544 StringRef::from_lit("yes"));
4547 // --backend-http1-connections-per-host
4548 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST,
4552 // --listener-disable-timeout
4553 cmdcfgs.emplace_back(SHRPX_OPT_LISTENER_DISABLE_TIMEOUT,
4557 // --strip-incoming-x-forwarded-for
4558 cmdcfgs.emplace_back(SHRPX_OPT_STRIP_INCOMING_X_FORWARDED_FOR,
4559 StringRef::from_lit("yes"));
4562 // --accesslog-format
4563 cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_FORMAT, StringRef{optarg});
4566 // --backend-http1-connections-per-frontend
4567 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND,
4571 // --tls-ticket-key-file
4572 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_FILE, StringRef{optarg});
4576 cmdcfgs.emplace_back(SHRPX_OPT_RLIMIT_NOFILE, StringRef{optarg});
4579 // --backend-response-buffer
4580 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_RESPONSE_BUFFER,
4584 // --backend-request-buffer
4585 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_REQUEST_BUFFER,
4589 // --no-host-rewrite
4590 cmdcfgs.emplace_back(SHRPX_OPT_NO_HOST_REWRITE,
4591 StringRef::from_lit("yes"));
4595 cmdcfgs.emplace_back(SHRPX_OPT_NO_SERVER_PUSH,
4596 StringRef::from_lit("yes"));
4599 // --backend-http2-connections-per-worker
4600 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTIONS_PER_WORKER,
4604 // --fetch-ocsp-response-file
4605 cmdcfgs.emplace_back(SHRPX_OPT_FETCH_OCSP_RESPONSE_FILE,
4609 // --ocsp-update-interval
4610 cmdcfgs.emplace_back(SHRPX_OPT_OCSP_UPDATE_INTERVAL, StringRef{optarg});
4614 cmdcfgs.emplace_back(SHRPX_OPT_NO_OCSP, StringRef::from_lit("yes"));
4617 // --header-field-buffer
4618 cmdcfgs.emplace_back(SHRPX_OPT_HEADER_FIELD_BUFFER, StringRef{optarg});
4621 // --max-header-fields
4622 cmdcfgs.emplace_back(SHRPX_OPT_MAX_HEADER_FIELDS, StringRef{optarg});
4625 // --add-request-header
4626 cmdcfgs.emplace_back(SHRPX_OPT_ADD_REQUEST_HEADER, StringRef{optarg});
4630 cmdcfgs.emplace_back(SHRPX_OPT_INCLUDE, StringRef{optarg});
4633 // --tls-ticket-key-cipher
4634 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_CIPHER,
4639 cmdcfgs.emplace_back(SHRPX_OPT_HOST_REWRITE,
4640 StringRef::from_lit("yes"));
4643 // --tls-session-cache-memcached
4644 cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED,
4648 // --tls-ticket-key-memcached
4649 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED,
4653 // --tls-ticket-key-memcached-interval
4654 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_INTERVAL,
4658 // --tls-ticket-key-memcached-max-retry
4659 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_RETRY,
4663 // --tls-ticket-key-memcached-max-fail
4664 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_FAIL,
4669 cmdcfgs.emplace_back(SHRPX_OPT_MRUBY_FILE, StringRef{optarg});
4672 // --accept-proxy-protocol
4673 cmdcfgs.emplace_back(SHRPX_OPT_ACCEPT_PROXY_PROTOCOL,
4674 StringRef::from_lit("yes"));
4678 cmdcfgs.emplace_back(SHRPX_OPT_FASTOPEN, StringRef{optarg});
4681 // --tls-dyn-rec-warmup-threshold
4682 cmdcfgs.emplace_back(SHRPX_OPT_TLS_DYN_REC_WARMUP_THRESHOLD,
4686 // --tls-dyn-rec-idle-timeout
4687 cmdcfgs.emplace_back(SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT,
4692 cmdcfgs.emplace_back(SHRPX_OPT_ADD_FORWARDED, StringRef{optarg});
4695 // --strip-incoming-forwarded
4696 cmdcfgs.emplace_back(SHRPX_OPT_STRIP_INCOMING_FORWARDED,
4697 StringRef::from_lit("yes"));
4701 cmdcfgs.emplace_back(SHRPX_OPT_FORWARDED_BY, StringRef{optarg});
4705 cmdcfgs.emplace_back(SHRPX_OPT_FORWARDED_FOR, StringRef{optarg});
4708 // --response-header-field-buffer
4709 cmdcfgs.emplace_back(SHRPX_OPT_RESPONSE_HEADER_FIELD_BUFFER,
4713 // --max-response-header-fields
4714 cmdcfgs.emplace_back(SHRPX_OPT_MAX_RESPONSE_HEADER_FIELDS,
4718 // --no-http2-cipher-black-list
4719 cmdcfgs.emplace_back(SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST,
4720 StringRef::from_lit("yes"));
4723 // --request-header-field-buffer
4724 cmdcfgs.emplace_back(SHRPX_OPT_REQUEST_HEADER_FIELD_BUFFER,
4728 // --max-request-header-fields
4729 cmdcfgs.emplace_back(SHRPX_OPT_MAX_REQUEST_HEADER_FIELDS,
4733 // --backend-http1-tls
4734 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP1_TLS,
4735 StringRef::from_lit("yes"));
4738 // --tls-session-cache-memcached-tls
4739 cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS,
4740 StringRef::from_lit("yes"));
4743 // --tls-session-cache-memcached-cert-file
4744 cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE,
4748 // --tls-session-cache-memcached-private-key-file
4749 cmdcfgs.emplace_back(
4750 SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE,
4754 // --tls-ticket-key-memcached-tls
4755 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS,
4756 StringRef::from_lit("yes"));
4759 // --tls-ticket-key-memcached-cert-file
4760 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE,
4764 // --tls-ticket-key-memcached-private-key-file
4765 cmdcfgs.emplace_back(
4766 SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE,
4770 // --tls-ticket-key-memcached-address-family
4771 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY,
4775 // --tls-session-cache-memcached-address-family
4776 cmdcfgs.emplace_back(
4777 SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY,
4781 // --backend-address-family
4782 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_ADDRESS_FAMILY,
4786 // --frontend-http2-max-concurrent-streams
4787 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS,
4791 // --backend-http2-max-concurrent-streams
4792 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS,
4796 // --backend-connections-per-frontend
4797 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND,
4802 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS, StringRef::from_lit("yes"));
4805 // --backend-connections-per-host
4806 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST,
4811 cmdcfgs.emplace_back(SHRPX_OPT_ERROR_PAGE, StringRef{optarg});
4815 cmdcfgs.emplace_back(SHRPX_OPT_NO_KQUEUE, StringRef::from_lit("yes"));
4818 // --frontend-http2-settings-timeout
4819 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_SETTINGS_TIMEOUT,
4823 // --backend-http2-settings-timeout
4824 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT,
4828 // --api-max-request-body
4829 cmdcfgs.emplace_back(SHRPX_OPT_API_MAX_REQUEST_BODY, StringRef{optarg});
4832 // --backend-max-backoff
4833 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_MAX_BACKOFF, StringRef{optarg});
4837 cmdcfgs.emplace_back(SHRPX_OPT_SERVER_NAME, StringRef{optarg});
4840 // --no-server-rewrite
4841 cmdcfgs.emplace_back(SHRPX_OPT_NO_SERVER_REWRITE,
4842 StringRef::from_lit("yes"));
4845 // --frontend-http2-optimize-write-buffer-size
4846 cmdcfgs.emplace_back(
4847 SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE,
4848 StringRef::from_lit("yes"));
4851 // --frontend-http2-optimize-window-size
4852 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE,
4853 StringRef::from_lit("yes"));
4856 // --frontend-http2-window-size
4857 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_WINDOW_SIZE,
4861 // --frontend-http2-connection-window-size
4862 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_SIZE,
4866 // --backend-http2-window-size
4867 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_WINDOW_SIZE,
4871 // --backend-http2-connection-window-size
4872 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE,
4876 // --frontend-http2-encoder-dynamic-table-size
4877 cmdcfgs.emplace_back(
4878 SHRPX_OPT_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE,
4882 // --frontend-http2-decoder-dynamic-table-size
4883 cmdcfgs.emplace_back(
4884 SHRPX_OPT_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE,
4888 // --backend-http2-encoder-dynamic-table-size
4889 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE,
4893 // --backend-http2-decoder-dynamic-table-size
4894 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE,
4899 cmdcfgs.emplace_back(SHRPX_OPT_ECDH_CURVES, StringRef{optarg});
4903 cmdcfgs.emplace_back(SHRPX_OPT_TLS_SCT_DIR, StringRef{optarg});
4906 // --backend-connect-timeout
4907 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECT_TIMEOUT,
4911 // --dns-cache-timeout
4912 cmdcfgs.emplace_back(SHRPX_OPT_DNS_CACHE_TIMEOUT, StringRef{optarg});
4915 // --dns-lookup-timeou
4916 cmdcfgs.emplace_back(SHRPX_OPT_DNS_LOOKUP_TIMEOUT, StringRef{optarg});
4920 cmdcfgs.emplace_back(SHRPX_OPT_DNS_MAX_TRY, StringRef{optarg});
4923 // --frontend-keep-alive-timeout
4924 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_KEEP_ALIVE_TIMEOUT,
4929 cmdcfgs.emplace_back(SHRPX_OPT_PSK_SECRETS, StringRef{optarg});
4932 // --client-psk-secrets
4933 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PSK_SECRETS, StringRef{optarg});
4936 // --client-no-http2-cipher-black-list
4937 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST,
4938 StringRef::from_lit("yes"));
4942 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_CIPHERS, StringRef{optarg});
4945 // --accesslog-write-early
4946 cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_WRITE_EARLY,
4947 StringRef::from_lit("yes"));
4950 // --tls-min-proto-version
4951 cmdcfgs.emplace_back(SHRPX_OPT_TLS_MIN_PROTO_VERSION,
4955 // --tls-max-proto-version
4956 cmdcfgs.emplace_back(SHRPX_OPT_TLS_MAX_PROTO_VERSION,
4960 // --redirect-https-port
4961 cmdcfgs.emplace_back(SHRPX_OPT_REDIRECT_HTTPS_PORT, StringRef{optarg});
4964 // --frontend-max-requests
4965 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_MAX_REQUESTS,
4970 cmdcfgs.emplace_back(SHRPX_OPT_SINGLE_THREAD,
4971 StringRef::from_lit("yes"));
4974 // --no-add-x-forwarded-proto
4975 cmdcfgs.emplace_back(SHRPX_OPT_NO_ADD_X_FORWARDED_PROTO,
4976 StringRef::from_lit("yes"));
4979 // --no-strip-incoming-x-forwarded-proto
4980 cmdcfgs.emplace_back(SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO,
4981 StringRef::from_lit("yes"));
4985 cmdcfgs.emplace_back(SHRPX_OPT_SINGLE_PROCESS,
4986 StringRef::from_lit("yes"));
4989 // --verify-client-tolerate-expired
4990 cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT_TOLERATE_EXPIRED,
4991 StringRef::from_lit("yes"));
4994 // --ignore-per-pattern-mruby-error
4995 cmdcfgs.emplace_back(SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR,
4996 StringRef::from_lit("yes"));
4999 // --tls-no-postpone-early-data
5000 cmdcfgs.emplace_back(SHRPX_OPT_TLS_NO_POSTPONE_EARLY_DATA,
5001 StringRef::from_lit("yes"));
5004 // --tls-max-early-data
5005 cmdcfgs.emplace_back(SHRPX_OPT_TLS_MAX_EARLY_DATA, StringRef{optarg});
5009 cmdcfgs.emplace_back(SHRPX_OPT_TLS13_CIPHERS, StringRef{optarg});
5012 // --tls13-client-ciphers
5013 cmdcfgs.emplace_back(SHRPX_OPT_TLS13_CLIENT_CIPHERS, StringRef{optarg});
5016 // --no-strip-incoming-early-data
5017 cmdcfgs.emplace_back(SHRPX_OPT_NO_STRIP_INCOMING_EARLY_DATA,
5018 StringRef::from_lit("yes"));
5021 // --no-http2-cipher-block-list
5022 cmdcfgs.emplace_back(SHRPX_OPT_NO_HTTP2_CIPHER_BLOCK_LIST,
5023 StringRef::from_lit("yes"));
5026 // --client-no-http2-cipher-block-list
5027 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLOCK_LIST,
5028 StringRef::from_lit("yes"));
5031 // --quic-bpf-program-file
5032 cmdcfgs.emplace_back(SHRPX_OPT_QUIC_BPF_PROGRAM_FILE,
5037 cmdcfgs.emplace_back(SHRPX_OPT_NO_QUIC_BPF, StringRef::from_lit("yes"));
5041 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_ALTSVC, StringRef{optarg});
5044 // --frontend-http3-read-timeout
5045 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_READ_TIMEOUT,
5049 // --frontend-quic-idle-timeout
5050 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_IDLE_TIMEOUT,
5054 // --frontend-quic-debug-log
5055 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_DEBUG_LOG,
5056 StringRef::from_lit("yes"));
5059 // --frontend-http3-window-size
5060 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_WINDOW_SIZE,
5064 // --frontend-http3-connection-window-size
5065 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE,
5069 // --frontend-http3-max-window-size
5070 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_MAX_WINDOW_SIZE,
5074 // --frontend-http3-max-connection-window-size
5075 cmdcfgs.emplace_back(
5076 SHRPX_OPT_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE,
5080 // --frontend-http3-max-concurrent-streams
5081 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_MAX_CONCURRENT_STREAMS,
5085 // --frontend-quic-early-data
5086 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_EARLY_DATA,
5087 StringRef::from_lit("yes"));
5090 // --frontend-quic-qlog-dir
5091 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_QLOG_DIR,
5095 // --frontend-quic-require-token
5096 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_REQUIRE_TOKEN,
5097 StringRef::from_lit("yes"));
5100 // --frontend-quic-congestion-controller
5101 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_CONGESTION_CONTROLLER,
5106 cmdcfgs.emplace_back(SHRPX_OPT_QUIC_SERVER_ID, StringRef{optarg});
5109 // --frontend-quic-secret-file
5110 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_SECRET_FILE,
5115 cmdcfgs.emplace_back(SHRPX_OPT_RLIMIT_MEMLOCK, StringRef{optarg});
5118 // --max-worker-processes
5119 cmdcfgs.emplace_back(SHRPX_OPT_MAX_WORKER_PROCESSES, StringRef{optarg});
5122 // --worker-process-grace-shutdown-period
5123 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_PROCESS_GRACE_SHUTDOWN_PERIOD,
5127 // --frontend-quic-initial-rtt
5128 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_INITIAL_RTT,
5140 if (argc - optind >= 2) {
5141 cmdcfgs.emplace_back(SHRPX_OPT_PRIVATE_KEY_FILE, StringRef{argv[optind++]});
5142 cmdcfgs.emplace_back(SHRPX_OPT_CERTIFICATE_FILE, StringRef{argv[optind++]});
5145 rv = process_options(mod_config(), cmdcfgs);
5150 if (event_loop() != 0) {
5154 LOG(NOTICE) << "Shutdown momentarily";
5156 delete_log_config();
5161 } // namespace shrpx
5163 int main(int argc, char **argv) { return run_app(shrpx::main, argc, argv); }