Create your own onion service using Drogon C++ web framework

Posted in C++, Getting Started with Tor, Tor setup by - August 03, 2024

Create your own onion service using Drogon C++ web framework

Tor, an acronym for The Onion Router, is an open-source software that is free to use and promotes anonymous interactions online. It routes internet traffic through a global volunteer-driven overlay network comprising over seven thousand relays. The use of Tor increases the challenge of tracing a user’s online activities.

Drogon is a HTTP application framework that’s developed using the C++ programming language and supports either C++20 or C++17 with Boost. It’s utilized to construct a multitude of web application server programs using C++. Drogon is a versatile, cross-platform framework that is compatible with Linux, macOS, FreeBSD, OpenBSD, HaikuOS, and Windows.

We suggest installing Docker if you’re planning to establish an Onion Service and host it yourself. Docker is a software platform designed to facilitate building, testing, and deploying applications with speed. It organizes software into uniform units known as containers, which incorporate all the necessary components for the software’s operation, such as libraries, system tools, code, and runtime. Docker enables swift deployment and scaling of applications in any environment, ensuring the smooth running of your code.

Also We suggest utilizing Docker Compose once Docker has been installed. Docker Compose serves as a utility for formulating and executing applications that involve multiple containers. It is instrumental in facilitating a smooth and productive development and deployment process. Docker Compose makes it straightforward to handle your entire application stack, including services, networks, and volumes, through a single, easily understood YAML configuration file. Consequently, all the services from your configuration file can be created and initiated with just one command.

In order to containerize a C++ Drogon Web Application using Docker, you need to download a public Drogon image from the Docker Hub registry. This can be done by executing the below command:

$ docker image pull drogonframework/drogon
Using default tag: latest
latest: Pulling from drogonframework/drogon
aece8493d397: Pull complete 
b11f61d989b4: Pull complete 
58807c8d4ddf: Pull complete 
99d8c1dedd58: Pull complete 
6eb25abdfcba: Pull complete 
f6b93a15acd0: Pull complete 
Digest: sha256:8375b3f136fc875882a781b6d87390378b1a13b1399c79a621274b34a4134ad3
Status: Downloaded newer image for drogonframework/drogon:latest
docker.io/drogonframework/drogon:latest

Then, create a folder called ‘my_project’, and create a folder called ‘drogon’ and placed inside the ‘my_project’ folder. You can use below command to create your own C++ Drogon Web Application project. The project name ‘my_app’ is used to create the Drogon web application project.

$ docker run -v ./drogon:/data/drogon drogonframework/drogon bash -c "cd /data/drogon && drogon_ctl create project my_app && cd my_app/build && cmake .. && make"
create a project named my_app
-- The CXX compiler identification is GNU 11.4.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/g++-11 - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for C++ include any
-- Looking for C++ include any - found
-- Looking for C++ include string_view
-- Looking for C++ include string_view - found
-- Looking for C++ include coroutine
-- Looking for C++ include coroutine - not found
-- Found Jsoncpp: /usr/include/jsoncpp  
-- jsoncpp version:1.9.5
-- Found OpenSSL: /usr/lib/x86_64-linux-gnu/libcrypto.so (found version "3.0.2")  
-- Found c-ares: /usr/include  
-- Looking for C++ include pthread.h
-- Looking for C++ include pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE  
-- Found UUID: /usr/lib/x86_64-linux-gnu/libuuid.so
-- Found ZLIB: /usr/lib/x86_64-linux-gnu/libz.so (found version "1.2.11") 
-- Found PostgreSQL: /usr/lib/x86_64-linux-gnu/libpq.so (found version "14.9")  
-- pg inc: /usr/include/postgresql
-- Found pg: /usr/lib/x86_64-linux-gnu/libpq.so  
-- Found SQLite3: /usr/lib/x86_64-linux-gnu/libsqlite3.so  
-- MySQL Include dir: /usr/include/mariadb
-- MySQL client libraries: /usr/lib/x86_64-linux-gnu/libmariadbclient.so
-- Found MySQL: /usr/lib/x86_64-linux-gnu/libmariadbclient.so  
-- Found Hiredis: /usr/lib/x86_64-linux-gnu/libhiredis.so  
-- Looking for C++ include filesystem
-- Looking for C++ include filesystem - found
-- Performing Test CXX_FILESYSTEM_NO_LINK_NEEDED
-- Performing Test CXX_FILESYSTEM_NO_LINK_NEEDED - Success
-- use c++17
-- Configuring done
-- Generating done
-- Build files have been written to: /data/drogon/my_app/build
[ 25%] Building CXX object CMakeFiles/my_app.dir/main.cc.o
[ 50%] Linking CXX executable my_app
[ 50%] Built target my_app
[ 75%] Building CXX object test/CMakeFiles/my_app_test.dir/test_main.cc.o
[100%] Linking CXX executable my_app_test
[100%] Built target my_app_test

Executing the docker command will mount your host’s ‘drogon’ folder to the container at ‘/data/drogon’. You can then execute multiple commands using the ‘drogonframework/drogon’ image. Initially, switch the working directory to ‘/data/drogon’, and then employ the ‘drogon_ctl’ command to establish a new project named ‘my_app’. Following this, proceed to build and compile the project.

Let’s look at the ‘drogon/my_app/main.cc’ file:

#include <drogon/drogon.h>
int main() {
    //Set HTTP listener address and port
    drogon::app().addListener("0.0.0.0", 5555);
    //Load config file
    //drogon::app().loadConfigFile("../config.json");
    //drogon::app().loadConfigFile("../config.yaml");
    //Run HTTP framework,the method will block in the internal event loop
    drogon::app().run();
    return 0;
}

The application use 5555 port to listen the incoming connection. Change the 5555 port to 80 port, then save the file. And rebuild and recompile your project by using below command:

$ docker run -v ./drogon:/data/drogon drogonframework/drogon bash -c "cd /data/drogon/my_app/build && cmake .. && make"
-- jsoncpp version:1.9.5
-- Found UUID: /usr/lib/x86_64-linux-gnu/libuuid.so
-- pg inc: /usr/include/postgresql
-- MySQL Include dir: /usr/include/mariadb
-- MySQL client libraries: /usr/lib/x86_64-linux-gnu/libmariadbclient.so
-- use c++17
-- Configuring done
-- Generating done
-- Build files have been written to: /data/drogon/my_app/build
Consolidate compiler generated dependencies of target my_app
[ 25%] Building CXX object CMakeFiles/my_app.dir/main.cc.o
[ 50%] Linking CXX executable my_app
[ 50%] Built target my_app
Consolidate compiler generated dependencies of target my_app_test
[100%] Built target my_app_test

Then, create a default landing page.

echo '<h1>Hello Drogon!</h1>' >> ./drogon/my_app/build/index.html

The configuration of Drogon C++ web framework is ready. Then, create two folders called ‘config’ and ‘hidden_service’, and create a new file ‘torrc’ and placed it inside ‘config’ folder. The torrc content should be as below:

HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 80 web:80

This is a Tor config file which configure Tor instance to run a onion hidden service. Your onion service listens the port 80, and redirect the request to the address web:80.

Then, create compose.yaml

services:
  web:
    image: drogonframework/drogon
    volumes:
      - ./drogon:/data/drogon
    command: ./my_app
    working_dir: /data/drogon/my_app/build
  tor:
    image: osminogin/tor-simple
    volumes:
      - ./config/torrc:/etc/tor/torrc
      - ./hidden_service:/var/lib/tor/hidden_service

This is the final directory structure looks like:

├── compose.yaml                  Docker Compose File
├── config                        Configuration file
│   └── torrc
├── drogon                        Drogon application file
│   └── my_app
└── hidden_service                Tor hidden service file

Following this, execute docker compose up to run the onion service with your own C++ drogon web application.

$ docker compose up
[+] Running 3/1
 ✔ Network onion-service_default  Created                                                                                               0.2s 
 ✔ Container onion-service-tor-1  Created                                                                                               0.0s 
 ✔ Container onion-service-web-1  Created                                                                                               0.0s 
Attaching to onion-service-tor-1, onion-service-web-1
onion-service-tor-1  | Mar 31 13:51:25.711 [notice] Tor 0.4.8.10 running on Linux with Libevent 2.1.12-stable, OpenSSL 3.1.2, Zlib 1.3, Liblzma 5.4.5, Libzstd 1.5.5 and Unknown N/A as libc.
onion-service-tor-1  | Mar 31 13:51:25.711 [notice] Tor can't help you if you use it wrong! Learn how to be safe at https://support.torproject.org/faq/staying-anonymous/
onion-service-tor-1  | Mar 31 13:51:25.711 [notice] Read configuration file "/etc/tor/torrc".
onion-service-tor-1  | Mar 31 13:51:25.714 [notice] Opening Socks listener on 127.0.0.1:9050
onion-service-tor-1  | Mar 31 13:51:25.715 [notice] Opened Socks listener connection (ready) on 127.0.0.1:9050
onion-service-tor-1  | Mar 31 13:51:25.000 [notice] Parsing GEOIP IPv4 file /usr/share/tor/geoip.
onion-service-tor-1  | Mar 31 13:51:25.000 [notice] Parsing GEOIP IPv6 file /usr/share/tor/geoip6.
onion-service-tor-1  | Mar 31 13:51:26.000 [notice] Bootstrapped 0% (starting): Starting
onion-service-tor-1  | Mar 31 13:51:26.000 [notice] Starting with guard context "default"
onion-service-tor-1  | Mar 31 13:51:27.000 [notice] Bootstrapped 5% (conn): Connecting to a relay
onion-service-tor-1  | Mar 31 13:51:27.000 [notice] Bootstrapped 10% (conn_done): Connected to a relay
onion-service-tor-1  | Mar 31 13:51:27.000 [notice] Bootstrapped 14% (handshake): Handshaking with a relay
onion-service-tor-1  | Mar 31 13:51:27.000 [notice] Bootstrapped 15% (handshake_done): Handshake with a relay done
onion-service-tor-1  | Mar 31 13:51:27.000 [notice] Bootstrapped 20% (onehop_create): Establishing an encrypted directory connection
onion-service-tor-1  | Mar 31 13:51:28.000 [notice] Bootstrapped 25% (requesting_status): Asking for networkstatus consensus
onion-service-tor-1  | Mar 31 13:51:28.000 [notice] Bootstrapped 30% (loading_status): Loading networkstatus consensus
onion-service-tor-1  | Mar 31 13:51:29.000 [notice] I learned some more directory information, but not enough to build a circuit: We have no usable consensus.
onion-service-tor-1  | Mar 31 13:51:29.000 [notice] Bootstrapped 40% (loading_keys): Loading authority key certs
onion-service-tor-1  | Mar 31 13:51:29.000 [notice] The current consensus has no exit nodes. Tor can only build internal paths, such as paths to onion services.
onion-service-tor-1  | Mar 31 13:51:29.000 [notice] Bootstrapped 45% (requesting_descriptors): Asking for relay descriptors
onion-service-tor-1  | Mar 31 13:51:29.000 [notice] I learned some more directory information, but not enough to build a circuit: We need more microdescriptors: we have 0/7489, and can only build 0% of likely paths. (We have 0% of guards bw, 0% of midpoint bw, and 0% of end bw (no exits in consensus, using mid) = 0% of path bw.)
onion-service-tor-1  | Mar 31 13:51:30.000 [notice] Bootstrapped 50% (loading_descriptors): Loading relay descriptors
onion-service-tor-1  | Mar 31 13:51:31.000 [notice] The current consensus contains exit nodes. Tor can build exit and internal paths.
onion-service-tor-1  | Mar 31 13:51:32.000 [notice] Bootstrapped 56% (loading_descriptors): Loading relay descriptors
onion-service-tor-1  | Mar 31 13:51:32.000 [notice] Bootstrapped 62% (loading_descriptors): Loading relay descriptors
onion-service-tor-1  | Mar 31 13:51:32.000 [notice] Bootstrapped 71% (loading_descriptors): Loading relay descriptors
onion-service-tor-1  | Mar 31 13:51:32.000 [notice] Bootstrapped 75% (enough_dirinfo): Loaded enough directory info to build circuits
onion-service-tor-1  | Mar 31 13:51:33.000 [notice] Bootstrapped 90% (ap_handshake_done): Handshake finished with a relay to build circuits
onion-service-tor-1  | Mar 31 13:51:33.000 [notice] Bootstrapped 95% (circuit_create): Establishing a Tor circuit
onion-service-tor-1  | Mar 31 13:51:33.000 [notice] Bootstrapped 100% (done): Done

Your onion service URL is in the file ./hidden_service/hostname. Open the Tor browser, and enter your onion service URL.

Open the Tor browser, and enter your onion service URL. Your onion service, with C++ Drogon web framework is configured successfully.

Your onion service, with C++ Drogon web framework is configured successfully.

Link to Tor Project

Link to Docker

Link to Docker Compose

Link to Drogon C++ web framework

This post was written by

Leave a Reply

Your email address will not be published. Required fields are marked *

Please enter and activate your license key for Cryptocurrency Widgets PRO plugin for unrestricted and full access of all premium features.