=== Server

Jooby supports multiple web server implementations. A server is automatically registered based on its presence on the project classpath.

Officially supported servers:

* javadoc:jetty.JettyServer[artifact=jooby-jetty]
* javadoc:netty.NettyServer[artifact=jooby-netty]
* javadoc:undertow.UndertowServer[artifact=jooby-undertow]
* javadoc:vertx.VertxServer[artifact=jooby-vertx]

To use a specific server, add the corresponding dependency to your project:

[dependency, artifactId="jooby-netty"]
.

[IMPORTANT]
====
Only **one** server dependency should be available on the classpath at a time.
====

==== Manual Setup

While Jooby usually loads the server automatically via the `ServiceLoader` API, you can also instantiate and configure a server manually in your `main` method.

This is particularly useful if you need to access server-specific features, such as configuring **Project Loom (Virtual Threads)** in Jetty:

.Jetty with Virtual Threads
[source,java,role="primary"]
----
import io.jooby.jetty.JettyServer;
import java.util.concurrent.Executors;
import org.eclipse.jetty.util.thread.QueuedThreadPool;

public static void main(String[] args) {
  var worker = new QueuedThreadPool();
  worker.setReservedThreads(0);
  worker.setVirtualThreadsExecutor(Executors.newVirtualThreadPerTaskExecutor());

  runApp(args, new JettyServer(worker), App::new);
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
import io.jooby.jetty.JettyServer
import java.util.concurrent.Executors
import org.eclipse.jetty.util.thread.QueuedThreadPool

fun main(args: Array<String>) {
  val worker = QueuedThreadPool().apply {
    reservedThreads = 0
    virtualThreadsExecutor = Executors.newVirtualThreadPerTaskExecutor()
  }

  runApp(args, JettyServer(worker), ::App)
}
----

==== Running Multiple Apps

Jooby servers can run multiple applications simultaneously.

.Multi-App Server
[source,java,role="primary"]
----
import io.jooby.netty.NettyServer;
import java.util.List;

public static void main(String[] args) {
  runApp(args, new NettyServer(), List.of(FooApp::new, BarApp::new));
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
import io.jooby.netty.NettyServer

fun main(args: Array<String>) {
  runApp(args, NettyServer(), ::FooApp, ::BarApp)
}
----

[NOTE]
====
When running multiple apps, the server configuration (ports, threads, etc.) is determined by the first application setup that defines them.
====

==== Server Options

Server behavior can be controlled via the javadoc:ServerOptions[] class or through `application.conf`.

.Server Options
[source,java,role="primary"]
----
{
  var options = new ServerOptions()
      .setPort(8080)
      .setIoThreads(16)
      .setWorkerThreads(64)
      .setGzip(false)
      .setMaxRequestSize(10485760) // 10MB
      .setHttp2(true);
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  val options = ServerOptions().apply {
    port = 8080
    ioThreads = 16
    workerThreads = 64
    maxRequestSize = 10485760 // 10MB
    isHttp2 = true
  }
}
----

===== Core Settings

* `server.port`: The HTTP port (default: `8080`). Use `0` for a random port.
* `server.ioThreads`: Number of IO threads (Netty/Undertow). Defaults to `Processors * 2`.
* `server.workerThreads`: Number of worker threads. Defaults to `ioThreads * 8`.
* `server.maxRequestSize`: Maximum request size in bytes. Exceeding this triggers a `413 Request Entity Too Large` response.
* `server.defaultHeaders`: Automatically sets `Date`, `Content-Type`, and `Server` headers.
* `server.expectContinue`: Enables support for `100-Continue` requests.

==== HTTPS Support

Jooby supports HTTPS out of the box using either **PKCS12** (default) or **X.509** certificates.

===== Hello HTTPS (Self-Signed)

For development, you can enable a self-signed certificate with one line:

.Self-Signed HTTPS
[source,java,role="primary"]
----
public static void main(String[] args) {
  var options = new ServerOptions().setSecurePort(8443);
  runApp(args, new NettyServer(options), App::new);
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
fun main(args: Array<String>) {
  val options = ServerOptions().setSecurePort(8443)
  runApp(args, NettyServer(options), ::App)
}
----

===== Valid Certificates (X.509 & PKCS12)

For production, you should use valid certificates (e.g., from Let's Encrypt). You can configure these in your code or via `application.conf`.

.X.509 Configuration
[source,properties]
----
server.ssl.type = X509
server.ssl.cert = "path/to/server.crt"
server.ssl.key = "path/to/server.key"
----

.PKCS12 Configuration
[source,properties]
----
server.ssl.type = PKCS12
server.ssl.cert = "path/to/server.p12"
server.ssl.password = "password"
----

===== Mutual TLS (Client Authentication)

To require clients to present a certificate, set the `clientAuth` mode to `REQUIRED`. This usually requires a **Trust Store** containing the certificates you trust.

.Mutual TLS
[source,java,role="primary"]
----
{
  var ssl = SslOptions.pkcs12("server.p12", "password")
    .setTrustCert(Paths.get("trust.crt"))
    .setClientAuth(SslOptions.ClientAuth.REQUIRED);

  var options = new ServerOptions().setSsl(ssl);
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  val ssl = SslOptions.pkcs12("server.p12", "password")
      .setTrustCert(Paths.get("trust.crt"))
      .setClientAuth(SslOptions.ClientAuth.REQUIRED)

  val options = ServerOptions().setSsl(ssl)
}
----

==== HTTP/2 Support

HTTP/2 is supported across all servers. To use it in a browser, you **must** enable HTTPS.

.Enable HTTP/2
[source,java,role="primary"]
----
{
  var options = new ServerOptions()
      .setHttp2(true)
      .setSecurePort(8443);
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  val options = ServerOptions().apply {
    isHttp2 = true
    securePort = 8443
  }
}
----

==== OpenSSL (Conscrypt)

By default, Jooby uses the JDK's built-in SSL engine. For better performance and features (like **TLS v1.3** on older Java versions), you can use the OpenSSL-backed https://github.com/google/conscrypt[Conscrypt] provider.

Simply add the dependency:

[dependency, artifactId="jooby-conscrypt"]
.
