Onion services expose a website served by a particular host anonymously over the tor network, making the site accessible via an onion address (which masks the underlying host).
You can follow the official guide here for setting up [an] onion service(s).
That said, the guide specifically guides you in creating a very simple html document using Apache or Nginx - at the default virtual host location (i.e.
/var/lib/www, served over port 80 from localhost).
It can also be a Node.js server, a Go application, a C++ service, a ktor app, a Java web application, etc. Anything that listens at the local address and responds to
http requests can be exposed over the tor network via an onion service.
With that said, you have the full extent of tooling available for building websites at your disposal when designing an onion service.
In response to your comment where you ask ❝What specific changes to the
torrc file need to be made?❞:
The guide walks you through creating two
torrc file changes in order to create an onion service exposing that plain-Jane HTML website over tor:
Add the line
This line tells the tor service to expose a hidden (anonymous) service over the tor network, using the directory
Add the line
HiddenServicePort 80 127.0.0.1:80
This line tells the tor service to proxy that hidden service it's exposing to a website/web service listening on port
80, at the local address
127.0.0.1:80. In the case of the guide, this is a proxy to the default virtual host for Apache or Nginx (the guide walks you through a very simple quick-start install of either, asking you to put a single HTML file in the default host directory).
Restart the tor service via
sudo systemctl restart tor (or the comparable command on your host). If all goes well, the service will restart and create the directory (or directories) you specified per
hostname file in the directory you specified for
HiddenServiceDir. This file will contain the onion address (v3) (your .onion hostname). The other files in the directory are your onion service keys and need to be kept private; To expose their content would allow others to impersonate your service, and this would defeat the purpose altogether.
The guide goes on to explain that you can add more addresses that serve that same anonymous site/service by adding more
HiddenServicePort lines, and that each subsequent
HiddenServicePort entry will refer to the hidden (onion) service specified at the last
HiddenServiceDir entry made.
This means that you can leverage additional entries for supporting a load balancing scenario over tor, or to setup several services under the same tor service (tor client on a particular host).
As such, at the end of the day - a tor website (or onion service) is simply a regular website (in the myriad of ways one can be built) exposed over tor.