I don’t know why I missed it the first time: the answer is prolog (see the comments for '$runtoplevel in boot/toplevel.pl).
My code now is:
:- initialization(my_program_main, main).
my_program_main :-
http_server([port(...)]), % starts http server in separate threads
prolog. % top level REPL
If I don’t have the call to prolog, the program halts. (If I don’t want the REPL, I suppose I could use thread_httpd:http_current_worker/2 or thread_httpd:current_server/5 and do a thread_join.)
See library(http/http_unix_daemon), enable_development_system/0. If you want a web server on Unix, I’d use this as a basis. Besides all the stuff dealing with Unix daemon processes in several scenarios (start as root to use an privileged port, (not) fork, relay messages to syslog, etc) it also does a lot of work in controlling interaction, setting up the server including HTTPS, etc. For a simple interactive session use e.g.