static int setup_microhttpd_server(RemoteServer *s,
                                   int fd,
                                   const char *key,
                                   const char *cert,
                                   const char *trust) {
        struct MHD_OptionItem opts[] = {
                { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
                { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
                { MHD_OPTION_LISTEN_SOCKET, fd},
                { MHD_OPTION_CONNECTION_MEMORY_LIMIT, 128*1024},
                { MHD_OPTION_END},
                { MHD_OPTION_END},
                { MHD_OPTION_END},
                { MHD_OPTION_END},
                { MHD_OPTION_END}};
        int opts_pos = 4;
        int flags =
                MHD_USE_DEBUG |
                MHD_USE_DUAL_STACK |
                MHD_USE_EPOLL |
                MHD_USE_ITC;

        const union MHD_DaemonInfo *info;
        int r, epoll_fd;
        MHDDaemonWrapper *d;

        assert(fd >= 0);

        r = fd_nonblock(fd, true);
        if (r < 0)
                return log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);

/* MHD_OPTION_STRICT_FOR_CLIENT is introduced in microhttpd 0.9.54,
 * and MHD_USE_PEDANTIC_CHECKS will be deprecated in future.
 * If MHD_USE_PEDANTIC_CHECKS is '#define'd, then it is deprecated
 * and we should use MHD_OPTION_STRICT_FOR_CLIENT. On the other hand,
 * if MHD_USE_PEDANTIC_CHECKS is not '#define'd, then it is not
 * deprecated yet and there exists an enum element with the same name.
 * So we can safely use it. */
#ifdef MHD_USE_PEDANTIC_CHECKS
        opts[opts_pos++] = (struct MHD_OptionItem)
                {MHD_OPTION_STRICT_FOR_CLIENT, 1};
#else
        flags |= MHD_USE_PEDANTIC_CHECKS;
#endif

        if (key) {
                assert(cert);

                opts[opts_pos++] = (struct MHD_OptionItem)
                        {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
                opts[opts_pos++] = (struct MHD_OptionItem)
                        {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};

                flags |= MHD_USE_TLS;

                if (trust)
                        opts[opts_pos++] = (struct MHD_OptionItem)
                                {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
        }

        d = new(MHDDaemonWrapper, 1);
        if (!d)
                return log_oom();

        d->fd = (uint64_t) fd;

        d->daemon = MHD_start_daemon(flags, 0,
                                     NULL, NULL,
                                     request_handler, NULL,
                                     MHD_OPTION_ARRAY, opts,
                                     MHD_OPTION_END);
        if (!d->daemon) {
                log_error("Failed to start µhttp daemon");
                r = -EINVAL;
                goto error;
        }

        log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
                  key ? "HTTPS" : "HTTP", fd, d);

        info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
        if (!info) {
                log_error("µhttp returned NULL daemon info");
                r = -EOPNOTSUPP;
                goto error;
        }

        epoll_fd = info->listen_fd;
        if (epoll_fd < 0) {
                log_error("µhttp epoll fd is invalid");
                r = -EUCLEAN;
                goto error;
        }

        r = sd_event_add_io(s->events, &d->io_event,
                            epoll_fd, EPOLLIN,
                            dispatch_http_event, d);
        if (r < 0) {
                log_error_errno(r, "Failed to add event callback: %m");
                goto error;
        }

        r = sd_event_source_set_description(d->io_event, "io_event");
        if (r < 0) {
                log_error_errno(r, "Failed to set source name: %m");
                goto error;
        }

        r = sd_event_add_time(s->events, &d->timer_event,
                              CLOCK_MONOTONIC, (uint64_t) -1, 0,
                              null_timer_event_handler, d);
        if (r < 0) {
                log_error_errno(r, "Failed to add timer_event: %m");
                goto error;
        }

        r = sd_event_source_set_description(d->timer_event, "timer_event");
        if (r < 0) {
                log_error_errno(r, "Failed to set source name: %m");
                goto error;
        }

        r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
        if (r < 0) {
                log_oom();
                goto error;
        }

        r = hashmap_put(s->daemons, &d->fd, d);
        if (r < 0) {
                log_error_errno(r, "Failed to add daemon to hashmap: %m");
                goto error;
        }

        s->active++;
        return 0;

error:
        MHD_stop_daemon(d->daemon);
        free(d->daemon);
        free(d);
        return r;
}