Knowledgebase / Self-hosting Guide / Create your own onion service using Ruby on Rails web framework

Create your own onion service using Ruby on Rails web application 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.

Ruby on Rails is a web application framework that includes everything needed to create database-backed web applications according to the Model-View-Controller (MVC) pattern.

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 Ruby on Rails Web Application using Docker, we're going to set up Ruby on Rails within a Docker container. This requires a Dockerfile. This file includes all the necessary commands for installing programs and libraries, using a syntax that's straightforward to understand.

Create a file called Dockerfile

FROM ruby:latest AS ruby-app

RUN gem install rails bundler socksify

WORKDIR /usr/src/app

RUN rails new .
RUN bundle install

CMD ["/usr/src/app/bin/rails", "server", "-p", "80"]

You can then build the Ruby image:

docker build -t ruby-app .

Docker Compose permits you to operate one or more Docker containers with ease. You can outline everything in YAML and save this file, allowing other developers to merely execute docker-compose up and get everything up and running rapidly. Subsequently, we'll generate the compose.yaml file and duplicate the following content into it:

services:
  web:
    image: ruby-app
    volumes:
      - ./app:/usr/src/app
    command: /usr/src/app/bin/rails server -b 0.0.0.0 -p 80
  tor:
    image: osminogin/tor-simple
    volumes:
      - ./config/torrc:/etc/tor/torrc
      - ./hidden_service:/var/lib/tor/hidden_service

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 an onion hidden service. Your onion service listens the port 80, and redirect the request to the address web:80.

This is the final directory structure looks like:

├── compose.yaml                  Docker Compose File
├── config                        Configuration file
│   └── torrc
├── app                           Ruby on Rails application file
└── hidden_service                Tor hidden service file

Following this, execute docker compose up to run the onion service with your own Ruby on Rails web application.

$ docker compose up
[+] Running 2/0
 ✔ 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  | Apr 01 03:15:14.184 [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  | Apr 01 03:15:14.184 [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  | Apr 01 03:15:14.184 [notice] Read configuration file "/etc/tor/torrc".
onion-service-tor-1  | Apr 01 03:15:14.188 [notice] Opening Socks listener on 127.0.0.1:9050
onion-service-tor-1  | Apr 01 03:15:14.188 [notice] Opened Socks listener connection (ready) on 127.0.0.1:9050
onion-service-tor-1  | Apr 01 03:15:14.000 [notice] Parsing GEOIP IPv4 file /usr/share/tor/geoip.
onion-service-tor-1  | Apr 01 03:15:14.000 [notice] Parsing GEOIP IPv6 file /usr/share/tor/geoip6.
onion-service-tor-1  | Apr 01 03:15:14.000 [notice] Bootstrapped 0% (starting): Starting
onion-service-tor-1  | Apr 01 03:15:14.000 [notice] Starting with guard context "default"
onion-service-web-1  | => Booting Puma
onion-service-web-1  | => Rails 7.1.3.2 application starting in development 
onion-service-web-1  | => Run `bin/rails server --help` for more startup options
onion-service-web-1  | Puma starting in single mode...
onion-service-web-1  | * Puma version: 6.4.2 (ruby 3.3.0-p0) ("The Eagle of Durango")
onion-service-web-1  | *  Min threads: 5
onion-service-web-1  | *  Max threads: 5
onion-service-web-1  | *  Environment: development
onion-service-web-1  | *          PID: 1
onion-service-web-1  | * Listening on http://0.0.0.0:80
onion-service-web-1  | Use Ctrl-C to stop
onion-service-tor-1  | Apr 01 03:15:15.000 [notice] Bootstrapped 5% (conn): Connecting to a relay
onion-service-tor-1  | Apr 01 03:15:15.000 [notice] Bootstrapped 10% (conn_done): Connected to a relay
onion-service-tor-1  | Apr 01 03:15:15.000 [notice] Bootstrapped 14% (handshake): Handshaking with a relay
onion-service-tor-1  | Apr 01 03:15:16.000 [notice] Bootstrapped 15% (handshake_done): Handshake with a relay done
onion-service-tor-1  | Apr 01 03:15:16.000 [notice] Bootstrapped 20% (onehop_create): Establishing an encrypted directory connection
onion-service-tor-1  | Apr 01 03:15:16.000 [notice] Bootstrapped 25% (requesting_status): Asking for networkstatus consensus
onion-service-tor-1  | Apr 01 03:15:16.000 [notice] Bootstrapped 30% (loading_status): Loading networkstatus consensus
onion-service-tor-1  | Apr 01 03:15:17.000 [notice] I learned some more directory information, but not enough to build a circuit: We have no usable consensus.
onion-service-tor-1  | Apr 01 03:15:17.000 [notice] Bootstrapped 40% (loading_keys): Loading authority key certs
onion-service-tor-1  | Apr 01 03:15:18.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  | Apr 01 03:15:18.000 [notice] Bootstrapped 45% (requesting_descriptors): Asking for relay descriptors
onion-service-tor-1  | Apr 01 03:15:18.000 [notice] I learned some more directory information, but not enough to build a circuit: We need more microdescriptors: we have 0/7606, 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  | Apr 01 03:15:19.000 [notice] Bootstrapped 50% (loading_descriptors): Loading relay descriptors
onion-service-tor-1  | Apr 01 03:15:20.000 [notice] The current consensus contains exit nodes. Tor can build exit and internal paths.
onion-service-tor-1  | Apr 01 03:15:21.000 [notice] Bootstrapped 56% (loading_descriptors): Loading relay descriptors
onion-service-tor-1  | Apr 01 03:15:21.000 [notice] Bootstrapped 62% (loading_descriptors): Loading relay descriptors
onion-service-tor-1  | Apr 01 03:15:21.000 [notice] Bootstrapped 70% (loading_descriptors): Loading relay descriptors
onion-service-tor-1  | Apr 01 03:15:21.000 [notice] Bootstrapped 75% (enough_dirinfo): Loaded enough directory info to build circuits
onion-service-tor-1  | Apr 01 03:15:22.000 [notice] Bootstrapped 90% (ap_handshake_done): Handshake finished with a relay to build circuits
onion-service-tor-1  | Apr 01 03:15:22.000 [notice] Bootstrapped 95% (circuit_create): Establishing a Tor circuit
onion-service-tor-1  | Apr 01 03:15:23.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 Ruby on Rails web framework is configured successfully.

Your onion service, with Ruby on Rails web framework is configured successfully. However, a warning message is displayed because the application does not authorize the onion address, thus preventing the onion address from accessing the Ruby on Rails application. Consequently, it is necessary to alter the app/config/environments/development.rb file to permit the specified onion address. In this case, the onion address is zuourwyo3mln73j3ofsz2zbdorknh6fk4ykop6yyllwvbsh2e53clead.onion. Following the Ruby on Rails "Host Authorization guide", append the following syntax to the file.

config.hosts << "zuourwyo3mln73j3ofsz2zbdorknh6fk4ykop6yyllwvbsh2e53clead.onion"

Re-run the docker compose up command, the Ruby on Rails landing page is shown as below.

Re-run the docker compose up command, the Ruby on Rails landing page is shown as below.

Link to Tor Project

Link to Docker

Link to Docker Compose

Link to Ruby on Rails web framework

Tags:
  • Onion Service
  • Web Framework
  • Docker
  • Docker Compose
  • Ruby on Rails
  • Ruby

24/7 Expert Support

Our experts are always on hand to help answer your questions, get you started, and grow your presence online. You can email us any time