How to Setup Darknet Lantern on Docker

THIS IS STILL A WORK IN PROGRESS

THIS POST IS FOR INFORMATIONAL PURPOSES ONLY AND IS STILL BEING UPDATED.

I WILL REMOVE THIS NOTE WHEN THE POST IS FINISHED.

I’VE ONLY HAD A FEW HOURS TO WORK ON THIS AND STILL NEED TIME TO WRAP EVERYTHING UP. SEE TO-DO LIST AT BOTTOM.


Introduction

I put together some step by step instructions and notes on the setup process for Darknet Lantern using Docker.

Relevant Links:

Installation Tutorial

http://blog.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/opsec/darknetlantern/index.html

Git Repo

http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/darknet-lantern

Lantern Server

http://hb6dzgsmzmu3dmiflhvhe5yreknxtjvvatodgsmunxqgdhyqcro7ztid.onion/


Multistage Dockerfile Build


# Stage 1: builder stage to clone the Darknet Lantern repository via its onion link.
FROM debian:bookworm-slim AS builder
LABEL stage="builder"
ENV DEBIAN_FRONTEND=noninteractive

# Install git, tor, torsocks, and other utilities to perform the git clone.
RUN apt-get update && \
    apt-get install -y tor git torsocks curl && \
    rm -rf /var/lib/apt/lists/*

# Create directory for cloning.
WORKDIR /src

# Build-time ARG for the onion repository URL.
ARG LANTERN_REPO="http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/darknet-lantern.git"

# Start tor in the background, wait for it to bootstrap, then use torsocks to clone.
RUN set -ex && \
    tor & \
    TOR_PID=$! && \
    sleep 10 && \
    torsocks git clone -v ${LANTERN_REPO} darknet-lantern && \
    kill ${TOR_PID}

# Stage 2: final image for Darknet Lantern (without tor/torsocks)
FROM debian:bookworm-slim
LABEL maintainer="c0mmando@hackliberty.org"
ENV DEBIAN_FRONTEND=noninteractive

# Install runtime dependencies and socat
RUN apt-get update && \
    apt-get install -y nginx php8.2-fpm python3 python3-pip curl socat && \
    apt-get install -y python3-pandas python3-requests python3-socks && \
    rm -rf /var/lib/apt/lists/*

# Copy the Darknet Lantern source from the builder stage.
RUN mkdir -p /srv/darknet-lantern
COPY --from=builder /src/darknet-lantern/ /srv/darknet-lantern/

# Configure nginx: copy your pre-made configuration.
COPY ./lantern_nginx_conf/lantern.conf /etc/nginx/sites-available/lantern.conf
RUN ln -sf /etc/nginx/sites-available/lantern.conf /etc/nginx/sites-enabled/ && \
    rm -f /etc/nginx/sites-enabled/default

# Expose the internal web service port (adjust as necessary).
EXPOSE 80 #NEED TO DOUBLE CHECK THIS

# Create an updated docker-entrypoint.sh that starts socat in the background.
RUN echo '#!/bin/bash' > /usr/local/bin/docker-entrypoint.sh && \
    echo 'set -e' >> /usr/local/bin/docker-entrypoint.sh && \
    echo '' >> /usr/local/bin/docker-entrypoint.sh && \
    echo '# Start socat to forward 127.0.0.1:9050 to tor-proxy:9050' >> /usr/local/bin/docker-entrypoint.sh && \
    echo 'echo "Starting socat to forward traffic from 127.0.0.1:9050 to tor-proxy:9050..."' >> /usr/local/bin/docker-entrypoint.sh && \
    echo 'socat TCP-LISTEN:9050,reuseaddr,fork TCP:tor-proxy:9050 &' >> /usr/local/bin/docker-entrypoint.sh && \
    echo '' >> /usr/local/bin/docker-entrypoint.sh && \
    echo 'echo "Starting php8.2-fpm..."' >> /usr/local/bin/docker-entrypoint.sh && \
    echo 'service php8.2-fpm start' >> /usr/local/bin/docker-entrypoint.sh && \
    echo '' >> /usr/local/bin/docker-entrypoint.sh && \
    echo 'echo "Starting nginx..."' >> /usr/local/bin/docker-entrypoint.sh && \
    echo 'nginx -g "daemon off;"' >> /usr/local/bin/docker-entrypoint.sh

RUN chmod +x /usr/local/bin/docker-entrypoint.sh

WORKDIR /srv/darknet-lantern

ENTRYPOINT [ "/usr/local/bin/docker-entrypoint.sh" ]
  1. docker‑compose Configuration
    • Three services are defined:
      • darknet-lantern: Built from our updated Dockerfile, it exposes its internal port (80) to be used by SWAG via the shared networks.
      • tor: Runs the separate Tor container using the osminogin/tor-simple image.
      • tor-proxy: Runs a seperate Tor container using the osminogin/tor-simple image with an open Tor proxy for proxying lantern requests over Tor.
      • swag: Runs the SWAG container (from the ghcr.io/linuxserver/swag image), acting as a reverse proxy and TLS terminator.
    • Two networks (tor and swag) are created so that SWAG can proxy traffic to the Darknet Lantern container and, if necessary, containers can communicate with the Tor container.
networks:
  tor:
  lantern:

services:
  darknet-lantern:
    build: .
    container_name: darknet-lantern
    volumes:
      - ./lantern_data:/srv/darknet-lantern/www/participants    # Persist Darknet Lantern application data if needed.
      - ./lantern_nginx_conf:/etc/nginx/sites-enabled   # persist your nginx configuration.
    networks:
      - tor
      - lantern
    restart: unless-stopped

  tor:
    image: osminogin/tor-simple
    container_name: tor
    volumes:
      - ./tor-data:/var/lib/tor
      - ./tor-data/torrc:/etc/tor/torrc
    networks:
      - tor
    restart: unless-stopped

  tor-proxy:
    image: osminogin/tor-simple
    container_name: tor-proxy
    volumes:
      - ./tor-proxy:/var/lib/tor
      - ./tor-proxy/torrc:/etc/tor
    networks:
      - tor


  1. Create Volume Folders and Create nginx conf
  • mkdir lantern_data && mkdir lantern_nginx_conf
  • cd lantern_nginx_conf
  • nano lantern.conf (enter default conf for now)
server {
        listen 4443;
        listen [::]:4443;
        server_name lantern.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion;

        root /srv/darknet-lantern/www/;
        location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        }

        index index.php;

                # optional read-only static php file without the searchbar, to display all links by default :
                # index static.php;
}

  1. Building & Running

    • To build and run the complete multi‑container setup, run:
      docker-compose up --build
      
  2. Create Onions

  • Create folders in the tor-data volume associated with your tor-simple container if you have not already and create the darknet lantern folder
    sudo mkdir -p $HOME/tor-data/torrc && sudo mkdir -p $HOME/tor-data/darknet-lantern
  1. Set Permissions
    sudo chmod 700 $HOME/tor-data/darknet-lantern && sudo chown 100:65533 $HOME/tor-data/darknet-lantern

  2. create tor-proxy folders
    a. sudo mkdir -p $HOME/tor-proxy/torrc && sudo chown -R 100:65533 $HOME/tor-proxy/ && sudo chmod -R 700 $HOME/tor-proxy/

  3. Add Firewall Rules
    a. sudo ufw allow 4443/tcp
    b. sudo ufw reload

  4. Add the following to torrc
    a. sudo nano $HOME/tor-data/torrc/torrc

 HiddenServiceDir /var/lib/tor/darknet-lantern
 HiddenServicePort 80 darknet-lantern:4443
  1. Update your lantern.conf file to include Tor hostname
    a. sudo cat $HOME/tor-data/darknet-lantern/hostname
    b. nano $HOME/lantern_nginx_conf/lantern.conf
server {
        listen 4443;
        listen [::]:4443;
        server_name UPDATEME.onion; 

        root /srv/darknet-lantern/www/;
        location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        }

        index index.php;

                # optional read-only static php file without the searchbar, to display all lin>
                # index static.php;
}
  1. Configure Tor Proxy
  • create torrc
    Do not use 0.0.0.0 unless your configuration requires it. For the purpose of this specific configuration, it is acceptable because docker container will only be accessible over tor docker network
    a. sudo echo "SocksPort 0.0.0.0:9050" > $HOME/tor-proxy/torrc/torrc
  • launch tor-proxy and check logs
    a. sudo docker compose up -d
    b. sudo docker logs tor-proxy should look something like
[..]
[notice] Read configuration file "/etc/tor/torrc"
[warn] You specified a public address '0.0.0.0:9050' for SocksPort. Other people on the Internet might find your computer and use it as an open proxy. Please dont allow this unless you have a good reason.
[notice] Opening Socks listener on 0.0.0.0:9050
[notice] Opened Socks listener connection (ready) on 0.0.0.0:9050
[..]

  1. Modified Dockerfile (reflected above already)
  • Installed socat:
    Added socat in the final image to forward connections from 127.0.0.1:9050 to the tor-proxy container.

  • Updated ENTRYPOINT:
    Modified docker-entrypoint.sh to run:
    socat TCP-LISTEN:9050,reuseaddr,fork TCP:tor-proxy:9050 &
    This ensures that the application’s hardcoded proxy (127.0.0.1:9050) is forwarded to tor-proxy:9050.

  • Network Configuration:
    Requires both containers to be on the same Docker network so that the hostname tor-proxy resolves correctly. (already in docker compose)


  1. Initialize Darknet Lantern
    a. sudo docker exec -it darknet-lantern python3 /scripts/lantern.py
    b. enter your onion hostname
    c. is this your instance domain? yes

  2. Add Webring Participants
    We need to populate the webring participant folder because our bind mount volume is set to participants and it is currently empty.
    a. Visit http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/darknet-lantern/src/branch/main/www/participants
    b. Add all the listed webring participants
    c. sudo docker exec -it darknet-lantern python3 /scripts/lantern.py
    d. Select Option 5 “Add a new webring participant”
    e. Select Option 4 “Synchronize new links”

  3. Browse to your onion URL and confirm website is being served

BONUS: Host Lantern on Clearnet using SWAG Reverse Proxy

  1. Add SWAG to docker-compose, this is what mine looks like:
  swag:
    image: ghcr.io/linuxserver/swag
    restart: unless-stopped
    container_name: swag
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=1000
      - PGID=1000
      - URL=${SWAG_URL}
      - SUBDOMAINS=${SWAG_SUBDOMAINS}
      - VALIDATION=http
      - EMAIL=${SWAG_EMAIL}
      - ONLY_SUBDOMAINS=false
    volumes:
      - ./swag:/config:Z
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 443:443
      - 80:80
    networks:
      - tor
      - lantern
    security_opt:
      - no-new-privileges:true
  1. Create the DNS Record for Lantern
    a. TYPE: A
    b. NAME: lantern.hackliberty.org
    c. IPV4: 93.95.228.245

  2. Add the subdomain to swag environment file (.env)
    a. SWAG_SUBDOMAINS=git, paste, ots, write, simplex, blog, www, lantern

  3. Add Nginx Lantern Site to Proxy connections to upstream container
    a. cd /swag/nginx/site-confs/
    b. nano lantern.conf

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name lantern.*;
    include /config/nginx/ssl.conf;

    location / {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        add_header Onion-Location http://hb6dzgsmzmu3dmiflhvhe5yreknxtjvvatodgsmunxqgdhyqcro7ztid.onion$request_uri;
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
        set $upstream_app darknet-lantern;
        set $upstream_port 4443;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}
  1. Restart Docker Compose to Pull LetsEncrypt Certs
    a. sudo docker compose up -d

  2. Check your instance is hosted over clearnet

https://lantern.hackliberty.org

To-Do List

  1. Implement optional clearnet section done
  2. Create a user for limited permissions
  3. Remove server name in lantern.conf if unnecessary leave it, its necessary
  4. Double check port 80 expose in Dockerfile – remove if unnecessary removed
  5. Double check port 4443 expose in docker-compose file – remove if unnecessary removed
  6. Clean up docker compose file – remove swag – add to optional section done
  7. Security hardening and explore alpine as container image
  8. Check website html for proper SEO meta tagging (oEmbed, OpenGraph)
  9. Setup or check for cron job – add it to Dockerfile if necessary
  10. Setup webring, banner, and explore themes
  11. Add verified and unverified links
3 Likes

(copy pasting from the lantern simplex chatroom)

Just to clarify on the long run vision for Darknet Lantern, ideally the project is about getting a big webring going, of at least 100 communities that are hosting their own lantern instances.

This means that there will be 100 communities organizing together to efficiently explore the darknet, like a team of 100 miners splitting up the work of exploring an entire cave system, that’s the vision behind it. The bigger the exploration team is, the better, hence the webring part of the project.

Right now darknet exploration really is just a one man/one community thing (see how many people/communities are running their own lists of links, without being aware of each other)

I’m sure many people out there are doing it, and overlapping in the work that should’ve already been done, this is a disorganized way of doing things, I want to organize this in the long run, so that no efforts are wasted, and everyone can benefit from it, effectively making a P2P search engine, for the darknet in the long run, that’ll solve the visibility and discoverability problem of the Darknet, which is the main blocker for people still clinging to the clearnet for visibility.

3 Likes