Project

General

Profile

[Solved] A proper way of nesting host/socket clauses ?

Added by DreamingCat over 2 years ago

Hi,

I am running a website that must be accessible via both IPv4 and IPv6 and also via both HTTP and HTTPS. Its business logic kind of depends on what combination used to access it.
So I installed lighty (on Linux, if that's important) and it is running what is essentially a default empty site by virtue of server.port=80 and server.bind=0.0.0.0 and that's ok. After reading this forum and other notes on good config practices I realized I have to implement what is essentially 4 vhosts for each combination of IPv4+http, IPv4+https, IPv6+http and IPv6+https. To my understanding this is because server.use-ipv6=enable and ssl.engine=enable both must be used on a per-socket basis, so this is what I finally came up with:

$HTTP["host"] == "ccc.org.ua" {
        $SERVER["socket"] == "[::]:80" {
                server.use-ipv6 = "enable" 
                ssl.engine = "disable" 
                include "ccc.org.ua.conf" 
        }
#
        $SERVER["socket"] == "0.0.0.0:80" {
                ssl.engine = "disable" 
                include "ccc.org.ua.conf" 
        }
#
        $SERVER["socket"] == "[::]:443" {
                include "ssl_enable.conf" 
                include "ccc.org.ua.conf" 
        }
#
        $SERVER["socket"] == "0.0.0.0:443" {
                include "ssl_enable.conf" 
                include "ccc.org.ua.conf" 
        }
}

Here ssl_enable.conf include ssl.engine=enabled and other TLS fine-tuning but no domain-specific config. And ccc.org.ua sets vhost config and TLS certificates.
It works. By trial and error I found out you can't specify SSL certs under host clause, nor can you somehow merge clauses for IPv4 and IPv6 even if the expected behavior is the same.
Yet, with this config every time lighty starts it gives me a warning:
SSL: no certificate/private key for TLS server name .  $SERVER["socket"] should not be nested in other conditions.

It's a bit unclear on the "server name ." part but I understand part about socket nesting.
In theory I can rewrite config so that host clauses are nested inside socket clause but then SSL config wouldn't work for the aforementioned reasons.

So is there better or more elegant solution to this?
Thanks in advance.


Replies (6)

RE: A proper way of nesting host/socket clauses ? - Added by gstrauss over 2 years ago

It is a bad idea to nest $SERVER["socket"] inside any other condition, and might be an error in the upcoming lighttpd 1.4.60.

Configuration: File Syntax

$SERVER["socket"] ... Valid in global scope. Placing $SERVER["socket"] inside other conditions may have undesirable results (and would be rejected if not for historic (mis)use).

lighttpd TLS docs

Note: ssl.* configuration options are generally valid only in global scope or in the top level of a $SERVER["socket"] configuration condition, as they are needed when the socket connection is established, before the host is known. In cases where the client adds SNI (server name indication), some ssl.* options can be specified in $HTTP["host"] or $HTTP["scheme"] conditions, e.g. to select certificates for that specific connection. All other conditions occur after TLS negotiation has completed, so ssl.* directives nested in other configuration conditions may be ignored, including $SERVER["socket"] or $HTTP["host"] or $HTTP["scheme"] nested in other configuration conditions.

Since clients might make requests without providing a Host header, you need default configs for each listening socket. For the default server.port=80 and server.bind=0.0.0.0 (which can be changed), server.document-root is what is used. For TLS, you additionally need to configure a default certificate, which can be self-signed if you merely want a throw-away response.

Why do you think you need to use server.use-ipv6 = "enable"? It is always enabled with an IPv6 address. I do not think that you need it.

This template might help you:

server.document-root = "/path/to/default/host/docroot" 
$SERVER["socket"] == "0.0.0.0:80" { }
$SERVER["socket"] == "[::]:80"    { }

ssl.pemfile = "/path/to/default/host/certs/cert.pem" 
$SERVER["socket"] == "0.0.0.0:443" { ssl.engine = "enable" }
$SERVER["socket"] == "[::]:443"    { ssl.engine = "enable" }

# You could list this once if the rest of the config is shared,
# and could even add the $HTTP["host"] == "ccc.org.ua" { ... } to the include file.
# Definitions for ssl.pemfile for the virtual host are used when ssl.engine = "enable" 
# and have no effect on sockets where TLS is not enabled.
#
$HTTP["host"] == "ccc.org.ua" {
    include "ccc.org.ua.conf" 
}

# If you additionally need to change config based on TLS or not,
# then you can differentiate your configs in two blocks,
# one for "http" and one for "https".  This could be part of
# "ccc.org.ua.conf" if the behavior is for specific virtual hosts
# and can not be generalized here.
#
$HTTP["scheme"] == "https" {

}
else {

}

RE: A proper way of nesting host/socket clauses ? - Added by gstrauss over 2 years ago

SSL: no certificate/private key for TLS server name . $SERVER["socket"] should not be nested in other conditions.

That might be clearer as TLS server name "". lighttpd did not have a valid server name or TLS certificate configured at the point where this error was presented. This can happen if you made a TLS connection directly to the IP address, without using an SNI host name. As mentioned above, nesting $SERVER["socket"] inside other conditions is an error.

RE: A proper way of nesting host/socket clauses ? - Added by gstrauss over 2 years ago

BTW, you can include your "ssl_enable.conf" in the global setting for all TLS sockets to inherit those tunings, but omit ssl.engine = "enable" from the include if you use the template above.

Alternatively, you can invert the logic and set

server.port = 443
include "ssl_enable.conf" 
ssl.pemfile = "/path/to/default/host/certs/cert.pem" 
$SERVER["socket"] == "0.0.0.0:80"  { ssl.engine = "disable" }
$SERVER["socket"] == "[::]:80"     { ssl.engine = "disable" }
$SERVER["socket"] == "0.0.0.0:443" { }
$SERVER["socket"] == "[::]:443"    { }

RE: A proper way of nesting host/socket clauses ? - Added by DreamingCat over 2 years ago

Thanks for the answer.
So I tried the template you provided like this:

# ===> Enable all 4 proto combinations (ipv4+http, ipv4+https, ipv6+http, ipv6+https)
#
$SERVER["socket"] == "0.0.0.0:80" { }
$SERVER["socket"] == "[::]:80"    { }
#
ssl.pemfile = "/www/default/certs/default.pem" 
ssl.ca-file = "/www/default/certs/ca.crt" 
$SERVER["socket"] == "0.0.0.0:443" { ssl.engine = "enable" }
$SERVER["socket"] == "[::]:443"    { ssl.engine = "enable" }
#
# ===> Common SSL/TLS tuning
#
include "ssl_enable.conf" 
#
# ===> ccc.org.ua
#
$HTTP["host"] == "ccc.org.ua" {
        include "ccc.org.ua.conf" 
}

But with this config only HTTPS is now working (both over IPv4 and IPv6). HTTP is not working on either IP version, just forcibly closing the connection instead of any response. I wrote a simple test script using Curl that tries to connect to the server in all 4 possible combinations, and now two of them fail (ipv4+http and ipv6+http). The error log shows this:

2021-09-26 12:06:19: server.c.1566) server started (lighttpd/1.4.60-devel-lighttpd-1.4.59-396-g6ffabc96)
2021-09-26 12:06:22: mod_openssl.c.3292) SSL: error:140BA0C3:SSL routines:SSL_new:null ssl ctx
2021-09-26 12:06:22: mod_openssl.c.3292) SSL: error:140BA0C3:SSL routines:SSL_new:null ssl ctx
2021-09-26 12:06:23: mod_openssl.c.3292) SSL: error:140BA0C3:SSL routines:SSL_new:null ssl ctx
2021-09-26 12:06:23: mod_openssl.c.3292) SSL: error:140BA0C3:SSL routines:SSL_new:null ssl ctx
2021-09-26 12:06:27: server.c.1019) [note] graceful shutdown started
2021-09-26 12:06:27: server.c.2070) server stopped by UID = 0 PID = 0
2021-09-26 12:06:27: server.c.2070) server stopped by UID = 0 PID = 0

I am confused as to what to do.

RE: A proper way of nesting host/socket clauses ? - Added by DreamingCat over 2 years ago

BTW, you can include your "ssl_enable.conf" in the global setting for all TLS sockets to inherit those tunings, but omit ssl.engine = "enable" from the include if you use the template above.

Oh, yes, that was the reason. Thank you again, it is now seems to be working as intended.

RE: [Solved] A proper way of nesting host/socket clauses ? - Added by gstrauss over 2 years ago

BTW, ssl.ca-file = "/www/default/certs/ca.crt" is discouraged in new configs unless you are configuring ssl.ca-file for use with client certificate verification.
Instead, you should include the intermediate certificates in ssl.pemfile.
Please see lighttpd TLS docs for more details.

    (1-6/6)