├── .gitignore ├── LICENSE ├── README.md ├── mytest ├── tor-fied-etherpad ├── LICENSE ├── README.md ├── docker-compose.yml ├── etherpad_build │ ├── Dockerfile │ └── entrypoint.sh └── tor_build │ ├── Dockerfile │ └── assets │ ├── entrypoint-config.yml │ ├── onions │ ├── onions │ │ ├── Onions.py │ │ ├── Service.py │ │ └── __init__.py │ ├── setup.py │ └── tests │ │ └── onions_test.py │ ├── torrc │ └── v3onions ├── tor-fied-ghost ├── LICENSE ├── README.md ├── docker-compose.yml ├── docker-entrypoint.sh ├── ghost_build │ ├── Dockerfile │ └── docker-entrypoint.sh └── tor_build │ ├── Dockerfile │ └── assets │ ├── entrypoint-config.yml │ ├── onions │ ├── onions │ │ ├── Onions.py │ │ ├── Service.py │ │ └── __init__.py │ ├── setup.py │ └── tests │ │ └── onions_test.py │ ├── torrc │ └── v3onions ├── tor-fied-gitlab ├── docker-compose.yml └── tor_build │ ├── Dockerfile │ └── assets │ ├── entrypoint-config.yml │ ├── onions │ ├── onions │ │ ├── Onions.py │ │ ├── Service.py │ │ └── __init__.py │ ├── setup.py │ └── tests │ │ └── onions_test.py │ ├── torrc │ └── v3onions ├── tor-fied-lamp ├── LICENSE ├── README.md ├── docker-compose.yml ├── lamp_build │ ├── 000-default.conf │ ├── Dockerfile │ ├── apache2.conf │ └── other-vhosts-access-log.conf └── tor_build │ ├── Dockerfile │ └── assets │ ├── entrypoint-config.yml │ ├── onions │ ├── onions │ │ ├── Onions.py │ │ ├── Service.py │ │ └── __init__.py │ ├── setup.py │ └── tests │ │ └── onions_test.py │ ├── torrc │ └── v3onions ├── tor-fied-mediawiki ├── LICENSE ├── README.md ├── docker-compose.yml ├── mediawiki_build │ └── Dockerfile └── tor_build │ ├── Dockerfile │ └── assets │ ├── entrypoint-config.yml │ ├── onions │ ├── onions │ │ ├── Onions.py │ │ ├── Service.py │ │ └── __init__.py │ ├── setup.py │ └── tests │ │ └── onions_test.py │ ├── torrc │ └── v3onions ├── tor-fied-nextcloud ├── LICENSE ├── README.md ├── docker-compose.yml ├── nextcloud_build │ ├── Dockerfile │ ├── config │ │ ├── apcu.config.php │ │ ├── apps.config.php │ │ ├── autoconfig.php │ │ ├── redis.config.php │ │ └── smtp.config.php │ ├── cron.sh │ ├── entrypoint.sh │ └── upgrade.exclude └── tor_build │ ├── Dockerfile │ └── assets │ ├── entrypoint-config.yml │ ├── onions │ ├── onions │ │ ├── Onions.py │ │ ├── Service.py │ │ └── __init__.py │ ├── setup.py │ └── tests │ │ └── onions_test.py │ ├── torrc │ └── v3onions ├── tor-fied-nyancat ├── LICENSE ├── README.md ├── docker-compose.yml ├── nyan_build │ └── Dockerfile └── tor_build │ ├── Dockerfile │ └── assets │ ├── entrypoint-config.yml │ ├── onions │ ├── onions │ │ ├── Onions.py │ │ ├── Service.py │ │ └── __init__.py │ ├── setup.py │ └── tests │ │ └── onions_test.py │ ├── torrc │ └── v3onions ├── tor-fied-owncloud ├── LICENSE ├── README.md ├── docker-compose.yml └── tor_build │ ├── Dockerfile │ └── assets │ ├── entrypoint-config.yml │ ├── onions │ ├── onions │ │ ├── Onions.py │ │ ├── Service.py │ │ └── __init__.py │ ├── setup.py │ └── tests │ │ └── onions_test.py │ ├── torrc │ └── v3onions ├── tor-fied-paperwork ├── Dockerfile ├── README.md ├── docker-compose.yml ├── lighttpd.conf ├── paperwork.ico └── tor_build │ ├── Dockerfile │ └── assets │ ├── entrypoint-config.yml │ ├── onions │ ├── onions │ │ ├── Onions.py │ │ ├── Service.py │ │ └── __init__.py │ ├── setup.py │ └── tests │ │ └── onions_test.py │ ├── torrc │ └── v3onions ├── tor-fied-starwars ├── LICENSE ├── README.md ├── docker-compose.yml ├── starwars_build │ ├── Dockerfile │ ├── README.md │ ├── ascii-telnet-server.py │ └── sw1.txt └── tor_build │ ├── Dockerfile │ └── assets │ ├── entrypoint-config.yml │ ├── onions │ ├── onions │ │ ├── Onions.py │ │ ├── Service.py │ │ └── __init__.py │ ├── setup.py │ └── tests │ │ └── onions_test.py │ ├── torrc │ └── v3onions ├── tor-fied-tomcat ├── LICENSE ├── README.md ├── docker-compose.yml └── tor_build │ ├── Dockerfile │ └── assets │ ├── entrypoint-config.yml │ ├── onions │ ├── onions │ │ ├── Onions.py │ │ ├── Service.py │ │ └── __init__.py │ ├── setup.py │ └── tests │ │ └── onions_test.py │ ├── torrc │ └── v3onions ├── tor-fied-web ├── LICENSE ├── README.md ├── docker-compose.yml ├── tor_build │ ├── Dockerfile │ └── assets │ │ ├── entrypoint-config.yml │ │ ├── onions │ │ ├── onions │ │ │ ├── Onions.py │ │ │ ├── Service.py │ │ │ └── __init__.py │ │ ├── setup.py │ │ └── tests │ │ │ └── onions_test.py │ │ ├── torrc │ │ └── v3onions └── web_build │ ├── 000-default.conf │ ├── Dockerfile │ ├── apache2.conf │ ├── default-server.conf │ └── global.conf └── tor-fied-wordpress ├── LICENSE ├── README.md ├── docker-compose.yml └── tor_build ├── Dockerfile └── assets ├── entrypoint-config.yml ├── onions ├── onions │ ├── Onions.py │ ├── Service.py │ └── __init__.py ├── setup.py └── tests │ └── onions_test.py ├── torrc └── v3onions /.gitignore: -------------------------------------------------------------------------------- 1 | **/.data 2 | **/.tor 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tor Docker Compose Scripts 2 | 3 | The Docker Compose scripts here will allow you to install these web applications locally and as [Tor onion services](https://2019.www.torproject.org/docs/onion-services.html.en). 4 | 5 | Each compose scripts should have two main parts: 6 | 7 | 1. The Tor service 8 | 2. The web application 9 | 10 | ### Tor Service Example: 11 | 12 | ``` 13 | tor: 14 | build: tor_build/ 15 | links: 16 | - ghost 17 | restart: always 18 | # Keep keys in volumes 19 | volumes: 20 | - ".tor/:/var/lib/tor/hidden_service/" 21 | environment: 22 | # Set mapping ports 23 | GHOST_PORTS: "80:2368" 24 | ``` 25 | 26 | In this example, the Tor service will be built from source to ensure that you are getting the latest version of the code and that it is compatible with your CPU architecture. Also, the .onion service will be publishing this app on port 80 while the app is expecting it to be coming in on port 2368. 27 | 28 | ### Web Application Example: 29 | 30 | ``` 31 | ghost: 32 | build: ghost_build/ 33 | restart: always 34 | ports: 35 | - 2368:2368 36 | ``` 37 | 38 | In this example you can see that again we are building the app from source. The app will be available locally as http://localhost:2368. Remove the *ports* lines in order to make this app only available as an onion service and not a locally available service. 39 | 40 | ### About [Tor](https://torproject.org) 41 | 42 | The Tor image was originally published [here](https://github.com/cmehay/docker-tor-hidden-service) by [cmehay](https://github.com/cmehay). My fork is [here](https://github.com/tgeek77/tor-hidden-service). All images in this repository will be based on my [v3 Onion](https://github.com/tgeek77/tor-hidden-service/tree/v3) branch. 43 | 44 | Note: 45 | Not all scripts have been updated yet. I will be updating them to build the app and the Tor service from source as I have time. All scripts are testing on both x86 and ARM64 architectures. 46 | 47 | ### How to find my .onion address 48 | 49 | A simple script called *v3onions* is available in the Tor container to get the .onion url when the container is running. 50 | 51 | ``` 52 | $ docker exec my_tor_container v3onions 53 | /var/lib/tor/hidden_service/my_tor_container/hostname 54 | p7gyaqryx6hru34lodxorn7cr6jglnpe3huwzqffo6mogwkfwn6d7iyd.onion 55 | ``` 56 | ### Suggestions wanted! 57 | 58 | In the future, I hope to add scripts for Gitlab, Rocketchat, and maybe Mastadon. 59 | -------------------------------------------------------------------------------- /mytest: -------------------------------------------------------------------------------- 1 | hello world 2 | -------------------------------------------------------------------------------- /tor-fied-etherpad/README.md: -------------------------------------------------------------------------------- 1 | # tor-fied-wordpress 2 | ## Intro 3 | 4 | This is a docker-compose script for creating a simple wordpress hidden service onion. 5 | 6 | ### Special thanks to [cmehay](https://github.com/cmehay/docker-tor-hidden-service) and to the [Wordpress project](https://hub.docker.com/_/wordpress/) for their projects which allowed me to build this one. 7 | 8 | ### About the script: 9 | In truth, very little was done apart from copying and pasting from the two above mentioned projects into a new docker-compose file and tailoring it a little to make the two projects works together. 10 | 11 | #### Variables 12 | 13 | Volumes: By default, docker-compose will create a ~/.keys directory with the hostname and private key. You can change the local directory whatevery you want 14 | 15 | Passwords: Change the mysql root and user passwords to something other than the default passwords. Make sure that MYSQL_PASSWORD and WORDPRESS_DB_PASSWORD are the same password as they are referring to the same thing. 16 | 17 | ``` 18 | $ docker-compose up -d 19 | ``` 20 | #### What's my .onion url? 21 | 22 | Your new .onion hostname will be in ~/.keys/wordpress/hostname or you can run the following command: 23 | 24 | ``` 25 | $ docker exec -ti torfiedwordpress_tor_1 onions 26 | ``` 27 | 28 | #### Other applications 29 | 30 | I've used this process to create several other hidden service applications such as tomcat, jboss, as well as more commonplace webservers like apache and nginx. 31 | -------------------------------------------------------------------------------- /tor-fied-etherpad/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | services: 4 | tor: 5 | build: tor_build/ 6 | links: 7 | - db 8 | restart: always 9 | # Keep keys in volumes 10 | volumes: 11 | - .tor:/var/lib/tor/hidden_service 12 | environment: 13 | # Set mapping ports 14 | ETHERPAD_PORTS: "80:9001" 15 | 16 | db: 17 | image: mariadb 18 | restart: always 19 | environment: 20 | MYSQL_ROOT_PASSWORD: rootpass 21 | MYSQL_DATABASE: etherpad 22 | MYSQL_USER: wordpress 23 | MYSQL_PASSWORD: wordpress123 24 | volumes: 25 | - .data:/var/lib/mysql 26 | etherpad: 27 | build: etherpad_build/ 28 | depends_on: 29 | - db 30 | links: 31 | - db 32 | restart: always 33 | environment: 34 | ETHERPAD_DB_HOST: db 35 | ETHERPAD_DB_USER: root 36 | ETHERPAD_DB_PASSWORD: rootpass 37 | ETHERPAD_ADMIN_PASSWORD: admin 38 | ports: 39 | - 9001:9001 40 | -------------------------------------------------------------------------------- /tor-fied-etherpad/etherpad_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | MAINTAINER Tony Motakis 3 | 4 | ENV ETHERPAD_VERSION 1.6.5 5 | ENV NODE_ENV production 6 | 7 | RUN apt-get update && \ 8 | DEBIAN_FRONTEND=noninteractive apt-get install -y \ 9 | curl unzip mysql-client postgresql-client && \ 10 | rm -r /var/lib/apt/lists/* 11 | 12 | RUN npm install pg 13 | 14 | WORKDIR /opt/ 15 | 16 | RUN curl -SL \ 17 | https://github.com/ether/etherpad-lite/archive/${ETHERPAD_VERSION}.zip \ 18 | > etherpad.zip && unzip etherpad && rm etherpad.zip && \ 19 | mv etherpad-lite-${ETHERPAD_VERSION} etherpad-lite 20 | 21 | WORKDIR etherpad-lite 22 | 23 | RUN bin/installDeps.sh && rm settings.json 24 | COPY entrypoint.sh /entrypoint.sh 25 | 26 | RUN sed -i 's/^node/exec\ node/' bin/run.sh 27 | 28 | # OpenShift runs containers as non-root 29 | RUN chmod g+rwX,o+rwX -R . 30 | 31 | VOLUME /opt/etherpad-lite/var 32 | RUN ln -s var/settings.json settings.json 33 | 34 | EXPOSE 9001 35 | ENTRYPOINT ["/entrypoint.sh"] 36 | CMD ["bin/run.sh", "--root"] 37 | -------------------------------------------------------------------------------- /tor-fied-etherpad/etherpad_build/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | : ${ETHERPAD_DB_TYPE:=mysql} 5 | : ${ETHERPAD_DB_HOST:=mysql} 6 | : ${ETHERPAD_DB_PORT:=3306} 7 | : ${ETHERPAD_DB_USER:=root} 8 | : ${ETHERPAD_DB_NAME:=etherpad} 9 | : ${ETHERPAD_DB_CHARSET:=utf8mb4} 10 | ETHERPAD_DB_NAME=$( echo $ETHERPAD_DB_NAME | sed 's/\./_/g' ) 11 | 12 | # ETHERPAD_DB_PASSWORD is mandatory in mysql container, so we're not offering 13 | # any default. If we're linked to MySQL through legacy link, then we can try 14 | # using the password from the env variable MYSQL_ENV_MYSQL_ROOT_PASSWORD 15 | if [ "$ETHERPAD_DB_USER" = 'root' ]; then 16 | : ${ETHERPAD_DB_PASSWORD:=$MYSQL_ENV_MYSQL_ROOT_PASSWORD} 17 | fi 18 | 19 | if [ -n "$ETHERPAD_DB_PASSWORD_FILE" ]; then 20 | : ${ETHERPAD_DB_PASSWORD:=$(cat $ETHERPAD_DB_PASSWORD_FILE)} 21 | fi 22 | 23 | if [ -z "$ETHERPAD_DB_PASSWORD" ]; then 24 | echo >&2 'error: missing required ETHERPAD_DB_PASSWORD environment variable' 25 | echo >&2 ' Did you forget to -e ETHERPAD_DB_PASSWORD=... ?' 26 | echo >&2 27 | echo >&2 ' (Also of interest might be ETHERPAD_DB_PASSWORD_FILE, ETHERPAD_DB_USER and ETHERPAD_DB_NAME.)' 28 | exit 1 29 | fi 30 | 31 | : ${ETHERPAD_TITLE:=Etherpad} 32 | : ${ETHERPAD_PORT:=9001} 33 | 34 | # Check if database already exists 35 | if [ "$ETHERPAD_DB_TYPE" == 'mysql' ]; then 36 | RESULT=`mysql -u${ETHERPAD_DB_USER} -p${ETHERPAD_DB_PASSWORD} --port=${ETHERPAD_DB_PORT} \ 37 | -h${ETHERPAD_DB_HOST} --skip-column-names \ 38 | -e "SHOW DATABASES LIKE '${ETHERPAD_DB_NAME}'"` 39 | 40 | if [ "$RESULT" != $ETHERPAD_DB_NAME ]; then 41 | # mysql database does not exist, create it 42 | echo "Creating database ${ETHERPAD_DB_NAME}" 43 | 44 | mysql -u${ETHERPAD_DB_USER} -p${ETHERPAD_DB_PASSWORD} -h${ETHERPAD_DB_HOST} --port=${ETHERPAD_DB_PORT} \ 45 | -e "create database ${ETHERPAD_DB_NAME}" 46 | fi 47 | fi 48 | if [ "$ETHERPAD_DB_TYPE" == 'postgres' ]; then 49 | export PGPASSWORD=${ETHERPAD_DB_PASSWORD} 50 | if psql -U ${ETHERPAD_DB_USER} -h ${ETHERPAD_DB_HOST} postgres -lqt | cut -d \| -f 1 | grep -qw ${ETHERPAD_DB_NAME}; then 51 | true 52 | else 53 | # postgresql database does not exist, create it 54 | echo "Creating database ${ETHERPAD_DB_NAME}" 55 | psql -U ${ETHERPAD_DB_USER} -h ${ETHERPAD_DB_HOST} postgres \ 56 | -c "create database ${ETHERPAD_DB_NAME}" 57 | fi 58 | fi 59 | 60 | if [ ! -f APIKEY.txt ] && [ ! -z "${ETHERPAD_API_KEY}" ] ; then 61 | echo "Creating APIKEY.txt as ETHERPAD_API_KEY is defined"; 62 | echo "${ETHERPAD_API_KEY}" > APIKEY.txt 63 | fi 64 | 65 | if [ ! -f settings.json ]; then 66 | 67 | cat <<- EOF > settings.json 68 | { 69 | "title": "${ETHERPAD_TITLE}", 70 | "ip": "0.0.0.0", 71 | "port": "${ETHERPAD_PORT}", 72 | "dbType" : "${ETHERPAD_DB_TYPE}", 73 | "dbSettings" : { 74 | "user" : "${ETHERPAD_DB_USER}", 75 | "host" : "${ETHERPAD_DB_HOST}", 76 | "port" : "${ETHERPAD_DB_PORT}", 77 | "password": "${ETHERPAD_DB_PASSWORD}", 78 | "database": "${ETHERPAD_DB_NAME}", 79 | "charset": "${ETHERPAD_DB_CHARSET}" 80 | }, 81 | EOF 82 | 83 | if [ -n "$ETHERPAD_ADMIN_PASSWORD" ]; then 84 | 85 | : ${ETHERPAD_ADMIN_USER:=admin} 86 | 87 | cat <<- EOF >> settings.json 88 | "users": { 89 | "${ETHERPAD_ADMIN_USER}": { 90 | "password": "${ETHERPAD_ADMIN_PASSWORD}", 91 | "is_admin": true 92 | } 93 | }, 94 | EOF 95 | fi 96 | 97 | cat <<- EOF >> settings.json 98 | } 99 | EOF 100 | fi 101 | 102 | exec "$@" 103 | -------------------------------------------------------------------------------- /tor-fied-etherpad/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-etherpad/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-etherpad/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-etherpad/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-etherpad/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-etherpad/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-etherpad/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-ghost/README.md: -------------------------------------------------------------------------------- 1 | # tor-fied-ghost 2 | ## Intro 3 | 4 | This is a docker-compose script for creating a simple Ghost installation. 5 | 6 | ### Special thanks to: 7 | 8 | [cmehay](https://github.com/cmehay/docker-docker-tor-hidden-service) 9 | [ghost](https://hub.docker.com/_/ghost/) 10 | 11 | for their projects which allowed me to build this one. 12 | 13 | ### About the script: 14 | In truth, very little was done apart from copying and pasting from the two above mentioned projects into a new docker-compose file and tailoring it a little to make the two projects works together. 15 | 16 | #### Variables 17 | 18 | Volumes: By default, docker-compose will create a ~/.keys directory with the hostname and private key. You can change the local directory whatevery you want 19 | 20 | ``` 21 | $ docker-compose up -d 22 | ``` 23 | #### What's my .onion url? 24 | 25 | Your new .onion hostname will be in ~/.keys/ghost/hostname or you can run the following command: 26 | 27 | ``` 28 | $ docker exec -ti torfiedghost_tor_1 onions 29 | ``` 30 | 31 | ### Problems 32 | * email isn't working -- see http://support.ghost.org/mail for more help with that. 33 | 34 | -------------------------------------------------------------------------------- /tor-fied-ghost/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | services: 4 | tor: 5 | build: tor_build/ 6 | links: 7 | - ghost 8 | restart: always 9 | # Keep keys in volumes 10 | volumes: 11 | - ".tor/:/var/lib/tor/hidden_service/" 12 | environment: 13 | # Set mapping ports 14 | GHOST_PORTS: "80:2368" 15 | 16 | ghost: 17 | build: ghost_build/ 18 | restart: always 19 | ports: 20 | - 2368:2368 21 | 22 | -------------------------------------------------------------------------------- /tor-fied-ghost/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # allow the container to be started with `--user` 5 | if [[ "$*" == node*current/index.js* ]] && [ "$(id -u)" = '0' ]; then 6 | find "$GHOST_CONTENT" \! -user node -exec chown node '{}' + 7 | exec gosu node "$BASH_SOURCE" "$@" 8 | fi 9 | 10 | if [[ "$*" == node*current/index.js* ]]; then 11 | baseDir="$GHOST_INSTALL/content.orig" 12 | for src in "$baseDir"/*/ "$baseDir"/themes/*; do 13 | src="${src%/}" 14 | target="$GHOST_CONTENT/${src#$baseDir/}" 15 | mkdir -p "$(dirname "$target")" 16 | if [ ! -e "$target" ]; then 17 | tar -cC "$(dirname "$src")" "$(basename "$src")" | tar -xC "$(dirname "$target")" 18 | fi 19 | done 20 | fi 21 | 22 | exec "$@" 23 | -------------------------------------------------------------------------------- /tor-fied-ghost/ghost_build/Dockerfile: -------------------------------------------------------------------------------- 1 | # https://docs.ghost.org/faq/node-versions/ 2 | # https://github.com/nodejs/LTS 3 | FROM node:10-slim 4 | 5 | # grab gosu for easy step-down from root 6 | ENV GOSU_VERSION 1.10 7 | RUN set -x \ 8 | && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture)" \ 9 | && wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture).asc" \ 10 | && export GNUPGHOME="$(mktemp -d)" \ 11 | && gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \ 12 | && gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \ 13 | && { command -v gpgconf && gpgconf --kill all || :; } \ 14 | && rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc \ 15 | && chmod +x /usr/local/bin/gosu \ 16 | && gosu nobody true 17 | 18 | ENV NODE_ENV production 19 | 20 | ENV GHOST_CLI_VERSION 1.12.0 21 | RUN set -eux; \ 22 | npm install -g "ghost-cli@$GHOST_CLI_VERSION"; \ 23 | npm cache clean --force 24 | 25 | ENV GHOST_INSTALL /var/lib/ghost 26 | ENV GHOST_CONTENT /var/lib/ghost/content 27 | 28 | ENV GHOST_VERSION 3.0.0 29 | 30 | RUN set -eux; \ 31 | mkdir -p "$GHOST_INSTALL"; \ 32 | chown node:node "$GHOST_INSTALL"; \ 33 | \ 34 | gosu node ghost install "$GHOST_VERSION" --db sqlite3 --no-prompt --no-stack --no-setup --dir "$GHOST_INSTALL"; \ 35 | \ 36 | # Tell Ghost to listen on all ips and not prompt for additional configuration 37 | cd "$GHOST_INSTALL"; \ 38 | gosu node ghost config --ip 0.0.0.0 --port 2368 --no-prompt --db sqlite3 --url http://localhost:2368 --dbpath "$GHOST_CONTENT/data/ghost.db"; \ 39 | gosu node ghost config paths.contentPath "$GHOST_CONTENT"; \ 40 | \ 41 | # make a config.json symlink for NODE_ENV=development (and sanity check that it's correct) 42 | gosu node ln -s config.production.json "$GHOST_INSTALL/config.development.json"; \ 43 | readlink -f "$GHOST_INSTALL/config.development.json"; \ 44 | \ 45 | # need to save initial content for pre-seeding empty volumes 46 | mv "$GHOST_CONTENT" "$GHOST_INSTALL/content.orig"; \ 47 | mkdir -p "$GHOST_CONTENT"; \ 48 | chown node:node "$GHOST_CONTENT"; \ 49 | \ 50 | # force install "sqlite3" manually since it's an optional dependency of "ghost" 51 | # (which means that if it fails to install, like on ARM/ppc64le/s390x, the failure will be silently ignored and thus turn into a runtime error instead) 52 | # see https://github.com/TryGhost/Ghost/pull/7677 for more details 53 | cd "$GHOST_INSTALL/current"; \ 54 | # scrape the expected version of sqlite3 directly from Ghost itself 55 | sqlite3Version="$(npm view . optionalDependencies.sqlite3)"; \ 56 | if ! gosu node yarn add "sqlite3@$sqlite3Version" --force; then \ 57 | # must be some non-amd64 architecture pre-built binaries aren't published for, so let's install some build deps and do-it-all-over-again 58 | savedAptMark="$(apt-mark showmanual)"; \ 59 | apt-get update; \ 60 | apt-get install -y --no-install-recommends python make gcc g++ libc-dev; \ 61 | rm -rf /var/lib/apt/lists/*; \ 62 | \ 63 | gosu node yarn add "sqlite3@$sqlite3Version" --force --build-from-source; \ 64 | \ 65 | apt-mark showmanual | xargs apt-mark auto > /dev/null; \ 66 | [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \ 67 | apt-get purge -y --auto-remove; \ 68 | fi; \ 69 | \ 70 | gosu node yarn cache clean; \ 71 | gosu node npm cache clean --force; \ 72 | npm cache clean --force; \ 73 | rm -rv /tmp/yarn* /tmp/v8* 74 | 75 | WORKDIR $GHOST_INSTALL 76 | VOLUME $GHOST_CONTENT 77 | 78 | COPY docker-entrypoint.sh /usr/local/bin 79 | ENTRYPOINT ["docker-entrypoint.sh"] 80 | 81 | EXPOSE 2368 82 | CMD ["node", "current/index.js"] 83 | -------------------------------------------------------------------------------- /tor-fied-ghost/ghost_build/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # allow the container to be started with `--user` 5 | if [[ "$*" == node*current/index.js* ]] && [ "$(id -u)" = '0' ]; then 6 | find "$GHOST_CONTENT" \! -user node -exec chown node '{}' + 7 | exec gosu node "$BASH_SOURCE" "$@" 8 | fi 9 | 10 | if [[ "$*" == node*current/index.js* ]]; then 11 | baseDir="$GHOST_INSTALL/content.orig" 12 | for src in "$baseDir"/*/ "$baseDir"/themes/*; do 13 | src="${src%/}" 14 | target="$GHOST_CONTENT/${src#$baseDir/}" 15 | mkdir -p "$(dirname "$target")" 16 | if [ ! -e "$target" ]; then 17 | tar -cC "$(dirname "$src")" "$(basename "$src")" | tar -xC "$(dirname "$target")" 18 | fi 19 | done 20 | fi 21 | 22 | exec "$@" 23 | -------------------------------------------------------------------------------- /tor-fied-ghost/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-ghost/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-ghost/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-ghost/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-ghost/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-ghost/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-ghost/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-gitlab/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | tor: 4 | build: tor_build/ 5 | links: 6 | - web 7 | volumes: 8 | - ".tor/:/var/lib/tor/hidden_service/" 9 | environment: 10 | WEB_PORTS: "80:80" 11 | 12 | web: 13 | image: 'gitlab/gitlab-ce:latest' 14 | restart: always 15 | hostname: 'gitlab.example.com' 16 | environment: 17 | GITLAB_OMNIBUS_CONFIG: | 18 | external_url 'https://gitlab.example.com' 19 | # Add any other gitlab.rb configuration here, each on its own line 20 | ports: 21 | - '80:80' 22 | - '443:443' 23 | - '2222:22' 24 | volumes: 25 | - '.config:/etc/gitlab' 26 | - '.logs:/var/log/gitlab' 27 | - '.data:/var/opt/gitlab' 28 | -------------------------------------------------------------------------------- /tor-fied-gitlab/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-gitlab/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-gitlab/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-gitlab/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-gitlab/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-gitlab/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-gitlab/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-lamp/README.md: -------------------------------------------------------------------------------- 1 | # tor-fied-lamp 2 | ## Intro 3 | 4 | These are docker-compose and dockerfile scripts for creating a simple vanilla lamp stack runing as a hidden service onion. 5 | 6 | #### Special thanks to [cmehay](https://github.com/cmehay/docker-docker-tor-hidden-service) for their projects which allowed me to build this one. 7 | 8 | #### About the scripts: 9 | 10 | docker-compose.yml calls on three images: 11 | 12 |
13 |
tor
14 |
tor is the docker images which published the lamp stack as a .onion website.
15 | 16 |
db
17 |
db uses the official mariadb image from http://hub.docker.com
18 | 19 |
apache
20 |
apache is my own image that is build by the attached dockerfile.
21 |
22 | 23 | Dockerfile uses ubuntu:latest and installs a list of packages including apache2, php, and some standard dependancies. The list of packages can be changed or added to as needed for your own personal needs. 24 | 25 | #### Variables 26 | 27 | Volumes: In the tor section, docker-compose will create a ~/.keys directory with the hostname and private key. In the apache section, it create ~/www which links to /var/www/html in the apache container. By default you will not be able to write to this directory. Use chmod to change permissions to something that you can use. You can change this local directory to whatever you want. 28 | 29 | Passwords: **Change all passwords to something other than the default passwords!** I included a basic starter database in the configuration to ease in setting up something like wordpress or whatever. 30 | 31 | #### Build & Run! 32 | 33 | ``` 34 | docker-compose build 35 | docker-compose up -d 36 | ``` 37 | you can now start running your app! 38 | 39 | #### Stop and remove 40 | 41 | ``` 42 | docker-compose down 43 | ``` 44 | 45 | #### What's my .onion url? 46 | 47 | Your new .onion hostname will be in ~/.keys/wordpress/hostname or you can run the following command: 48 | 49 | ``` 50 | $ docker exec -ti torfiedlamp_tor_1 onions 51 | ``` 52 | 53 | #### Setting up LAMP applications 54 | 55 | I have successfully install Joomla, Wordpress, Koken, and phpMyAdmin using this project. 56 | 57 | Joomla, Wordpress, etc. -- the database location should not be "localhost", instead it should be "db" as that is how you can connect to the remote database container. 58 | 59 | phpMyAdmin -- download and install the file from https://www.phpmyadmin.net/. Rename config.sample.inc.php to config.inc.php and make the following change: 60 | 61 | ``` 62 | $cfg['Servers'][$i]['host'] = 'localhost'; 63 | ``` 64 | 65 | Should be changed to: 66 | 67 | ``` 68 | $cfg['Servers'][$i]['host'] = 'db'; 69 | ``` 70 | 71 | You can then run phpMyAdmin using the mariadb root and password settings from docker-compose.yml 72 | -------------------------------------------------------------------------------- /tor-fied-lamp/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | services: 4 | tor: 5 | build: tor_build/ 6 | links: 7 | - apache 8 | volumes: 9 | - ".tor/:/var/lib/tor/hidden_service/" 10 | environment: 11 | APACHE_PORTS: "80:80" 12 | db: 13 | image: mariadb 14 | restart: always 15 | environment: 16 | MYSQL_ROOT_PASSWORD: rootpass 17 | MYSQL_DATABASE: myproject 18 | MYSQL_USER: userid 19 | MYSQL_PASSWORD: myproject123 20 | 21 | apache: 22 | depends_on: 23 | - db 24 | build: lamp_build/ 25 | links: 26 | - db:db 27 | restart: always 28 | volumes: 29 | - "~/www/:/var/www/html/" 30 | -------------------------------------------------------------------------------- /tor-fied-lamp/lamp_build/000-default.conf: -------------------------------------------------------------------------------- 1 | 2 | # The ServerName directive sets the request scheme, hostname and port that 3 | # the server uses to identify itself. This is used when creating 4 | # redirection URLs. In the context of virtual hosts, the ServerName 5 | # specifies what hostname must appear in the request's Host: header to 6 | # match this virtual host. For the default virtual host (this file) this 7 | # value is not decisive as it is used as a last resort host regardless. 8 | # However, you must set it for any further virtual host explicitly. 9 | #ServerName www.example.com 10 | 11 | ServerAdmin webmaster@localhost 12 | DocumentRoot /var/www/html 13 | 14 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, 15 | # error, crit, alert, emerg. 16 | # It is also possible to configure the loglevel for particular 17 | # modules, e.g. 18 | #LogLevel info ssl:warn 19 | 20 | ErrorLog ${APACHE_LOG_DIR}/error.log 21 | #CustomLog ${APACHE_LOG_DIR}/access.log combined 22 | 23 | #CustomLog /dev/null 24 | 25 | # For most configuration files from conf-available/, which are 26 | # enabled or disabled at a global level, it is possible to 27 | # include a line for only one particular virtual host. For example the 28 | # following line enables the CGI configuration for this host only 29 | # after it has been globally disabled with "a2disconf". 30 | #Include conf-available/serve-cgi-bin.conf 31 | 32 | 33 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 34 | -------------------------------------------------------------------------------- /tor-fied-lamp/lamp_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:bionic 2 | RUN apt-get update && apt-get install -y apache2 3 | RUN DEBIAN_FRONTEND=noninteractive apt-get -yq install php7.2 \ 4 | libapache2-mod-php7.2 \ 5 | php7.2-mysql \ 6 | php7.2-curl \ 7 | php7.2-gd \ 8 | php7.2-intl \ 9 | php-pear \ 10 | php-imagick \ 11 | php7.2-imap \ 12 | php-memcache \ 13 | php7.2-pspell \ 14 | php7.2-recode \ 15 | php7.2-sqlite3 \ 16 | php7.2-tidy \ 17 | php7.2-xmlrpc \ 18 | php7.2-xsl \ 19 | php7.2-mbstring \ 20 | php-gettext \ 21 | php-phpseclib \ 22 | php-tcpdf 23 | COPY apache2.conf /etc/apache2/ 24 | COPY 000-default.conf /etc/apache2/sites-available/ 25 | COPY other-vhosts-access-log.conf /etc/apache2/conf-available/other-vhosts-access-log.conf 26 | CMD /usr/sbin/apache2ctl -D FOREGROUND 27 | EXPOSE 80 28 | -------------------------------------------------------------------------------- /tor-fied-lamp/lamp_build/other-vhosts-access-log.conf: -------------------------------------------------------------------------------- 1 | # Define an access log for VirtualHosts that don't define their own logfile 2 | CustomLog /dev/null vhost_combined 3 | 4 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 5 | -------------------------------------------------------------------------------- /tor-fied-lamp/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-lamp/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-lamp/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-lamp/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-lamp/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-lamp/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-lamp/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-mediawiki/README.md: -------------------------------------------------------------------------------- 1 | # tor-fied-wiki 2 | ## Intro 3 | 4 | This is a docker-compose script for creating a simple MediaWiki installation. 5 | 6 | ### Special thanks to: 7 | 8 | [cmehay](https://github.com/cmehay/docker-docker-tor-hidden-service) 9 | [synctree](https://github.com/synctree/docker-mediawiki) 10 | 11 | for their projects which allowed me to build this one. 12 | 13 | ### About the script: 14 | In truth, very little was done apart from copying and pasting from the two above mentioned projects into a new docker-compose file and tailoring it a little to make the two projects works together. 15 | 16 | #### Variables 17 | 18 | Volumes: By default, docker-compose will create a ~/.keys directory with the hostname and private key. You can change the local directory whatevery you want 19 | 20 | Passwords: Change the mysql root and user passwords to something other than the default passwords. 21 | 22 | ``` 23 | $ docker-compose up -d 24 | ``` 25 | #### What's my .onion url? 26 | 27 | Your new .onion hostname will be in ~/.keys/wiki/hostname or you can run the following command: 28 | 29 | ``` 30 | $ docker exec -ti torfiedwiki_tor_1 onions 31 | ``` 32 | 33 | ### Problems 34 | * email isn't working 35 | * the env variables aren't being recognized for mediawiki so they have to be put in manually via the installer script. 36 | 37 | -------------------------------------------------------------------------------- /tor-fied-mediawiki/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | services: 4 | tor: 5 | build: tor_build/ 6 | links: 7 | - mediawiki 8 | restart: always 9 | # Keep keys in volumes 10 | volumes: 11 | - ".tor/:/var/lib/tor/hidden_service/" 12 | environment: 13 | # Set mapping ports 14 | MEDIAWIKI_PORTS: "80:80" 15 | db: 16 | image: mariadb 17 | restart: always 18 | environment: 19 | MYSQL_ROOT_PASSWORD: rootpass 20 | MYSQL_DATABASE: mediawiki 21 | MYSQL_USER: wikigod 22 | MYSQL_PASSWORD: wikipass123 23 | volumes: 24 | - ".db/:/var/lib/mysql" 25 | 26 | 27 | mediawiki: 28 | depends_on: 29 | - db 30 | build: mediawiki_build/ 31 | links: 32 | - db 33 | restart: always 34 | environment: 35 | MEDIAWIKI_DB_HOST: db:3306 36 | MEDIAWIKI_DB_USER: wikigod 37 | MEDIAWIKI_DB_PASSWORD: wikipass123 38 | 39 | -------------------------------------------------------------------------------- /tor-fied-mediawiki/mediawiki_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.2-apache 2 | 3 | # System dependencies 4 | RUN set -ex; \ 5 | \ 6 | apt-get update; \ 7 | apt-get install -y --no-install-recommends \ 8 | git \ 9 | imagemagick \ 10 | # Required for SyntaxHighlighting 11 | python3 \ 12 | ; \ 13 | rm -rf /var/lib/apt/lists/* 14 | 15 | # Install the PHP extensions we need 16 | RUN set -ex; \ 17 | \ 18 | savedAptMark="$(apt-mark showmanual)"; \ 19 | \ 20 | apt-get update; \ 21 | apt-get install -y --no-install-recommends \ 22 | libicu-dev \ 23 | ; \ 24 | \ 25 | docker-php-ext-install \ 26 | intl \ 27 | mbstring \ 28 | mysqli \ 29 | opcache \ 30 | ; \ 31 | \ 32 | pecl install apcu-5.1.16; \ 33 | docker-php-ext-enable \ 34 | apcu \ 35 | ; \ 36 | \ 37 | # reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies 38 | apt-mark auto '.*' > /dev/null; \ 39 | apt-mark manual $savedAptMark; \ 40 | ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \ 41 | | awk '/=>/ { print $3 }' \ 42 | | sort -u \ 43 | | xargs -r dpkg-query -S \ 44 | | cut -d: -f1 \ 45 | | sort -u \ 46 | | xargs -rt apt-mark manual; \ 47 | \ 48 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ 49 | rm -rf /var/lib/apt/lists/* 50 | 51 | # Enable Short URLs 52 | RUN a2enmod rewrite \ 53 | && { \ 54 | echo ''; \ 55 | echo ' RewriteEngine On'; \ 56 | echo ' RewriteCond %{REQUEST_FILENAME} !-f'; \ 57 | echo ' RewriteCond %{REQUEST_FILENAME} !-d'; \ 58 | echo ' RewriteRule ^ %{DOCUMENT_ROOT}/index.php [L]'; \ 59 | echo ''; \ 60 | } > "$APACHE_CONFDIR/conf-available/short-url.conf" \ 61 | && a2enconf short-url 62 | 63 | # set recommended PHP.ini settings 64 | # see https://secure.php.net/manual/en/opcache.installation.php 65 | RUN { \ 66 | echo 'opcache.memory_consumption=128'; \ 67 | echo 'opcache.interned_strings_buffer=8'; \ 68 | echo 'opcache.max_accelerated_files=4000'; \ 69 | echo 'opcache.revalidate_freq=60'; \ 70 | echo 'opcache.fast_shutdown=1'; \ 71 | echo 'opcache.enable_cli=1'; \ 72 | } > /usr/local/etc/php/conf.d/opcache-recommended.ini 73 | 74 | # SQLite Directory Setup 75 | RUN mkdir -p /var/www/data \ 76 | && chown -R www-data:www-data /var/www/data 77 | 78 | # Version 79 | ENV MEDIAWIKI_MAJOR_VERSION 1.32 80 | ENV MEDIAWIKI_BRANCH REL1_32 81 | ENV MEDIAWIKI_VERSION 1.32.1 82 | ENV MEDIAWIKI_SHA512 597af44ba140a50b4dfec9dd1a81db1c96e6672f33870ad15d9be875c4a7109eff57034e10762c45c47bad4afdfe27b96949dd6dd4bea24db6ea54bafd80c376 83 | 84 | # MediaWiki setup 85 | RUN curl -fSL "https://releases.wikimedia.org/mediawiki/${MEDIAWIKI_MAJOR_VERSION}/mediawiki-${MEDIAWIKI_VERSION}.tar.gz" -o mediawiki.tar.gz \ 86 | && echo "${MEDIAWIKI_SHA512} *mediawiki.tar.gz" | sha512sum -c - \ 87 | && tar -xz --strip-components=1 -f mediawiki.tar.gz \ 88 | && rm mediawiki.tar.gz \ 89 | && chown -R www-data:www-data extensions skins cache images 90 | -------------------------------------------------------------------------------- /tor-fied-mediawiki/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-mediawiki/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-mediawiki/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-mediawiki/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-mediawiki/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-mediawiki/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-mediawiki/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/README.md: -------------------------------------------------------------------------------- 1 | # tor-fied-wordpress 2 | ## Intro 3 | 4 | This is a docker-compose script for creating a simple wordpress hidden service onion. 5 | 6 | ### Special thanks to [cmehay](https://github.com/cmehay/docker-docker-tor-hidden-service) and to the [Wordpress project](https://hub.docker.com/_/wordpress/) for their projects which allowed me to build this one. 7 | 8 | ### About the script: 9 | In truth, very little was done apart from copying and pasting from the two above mentioned projects into a new docker-compose file and tailoring it a little to make the two projects works together. 10 | 11 | #### Variables 12 | 13 | Volumes: By default, docker-compose will create a ~/.keys directory with the hostname and private key. You can change the local directory whatevery you want 14 | 15 | Passwords: Change the mysql root and user passwords to something other than the default passwords. Make sure that MYSQL_PASSWORD and WORDPRESS_DB_PASSWORD are the same password as they are referring to the same thing. 16 | 17 | ``` 18 | $ docker-compose up -d 19 | ``` 20 | #### What's my .onion url? 21 | 22 | Your new .onion hostname will be in ~/.keys/wordpress/hostname or you can run the following command: 23 | 24 | ``` 25 | $ docker exec -ti torfiedwordpress_tor_1 onions 26 | ``` 27 | 28 | #### Other applications 29 | 30 | I've used this process to create several other hidden service applications such as tomcat, jboss, as well as more commonplace webservers like apache and nginx. 31 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | tor: 4 | build: tor_build/ 5 | links: 6 | - nextcloud 7 | restart: always 8 | # Keep keys in volumes 9 | volumes: 10 | - .tor:/var/lib/tor/hidden_service 11 | environment: 12 | # Set mapping ports 13 | NEXTCLOUD_PORTS: "80:80" 14 | db: 15 | image: mariadb 16 | restart: always 17 | environment: 18 | MYSQL_ROOT_PASSWORD: rootpass 19 | MYSQL_DATABASE: owncloud 20 | MYSQL_USER: cloudadmin 21 | MYSQL_PASSWORD: wordpress123 22 | volumes: 23 | - .db:/var/lib/mysql 24 | 25 | nextcloud: 26 | build: nextcloud_build/ 27 | ports: 28 | - 80:80 29 | links: 30 | - db 31 | volumes: 32 | - .nextcloud:/var/www/html 33 | restart: always 34 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/nextcloud_build/Dockerfile: -------------------------------------------------------------------------------- 1 | # DO NOT EDIT: created by update.sh from Dockerfile-alpine.template 2 | FROM php:7.3-fpm-alpine3.9 3 | 4 | # entrypoint.sh and cron.sh dependencies 5 | RUN set -ex; \ 6 | \ 7 | apk add --no-cache \ 8 | rsync \ 9 | ; \ 10 | \ 11 | rm /var/spool/cron/crontabs/root; \ 12 | echo '*/15 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data 13 | 14 | # install the PHP extensions we need 15 | # see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html 16 | RUN set -ex; \ 17 | \ 18 | apk add --no-cache --virtual .build-deps \ 19 | $PHPIZE_DEPS \ 20 | autoconf \ 21 | freetype-dev \ 22 | icu-dev \ 23 | libevent-dev \ 24 | libjpeg-turbo-dev \ 25 | libmcrypt-dev \ 26 | libpng-dev \ 27 | libmemcached-dev \ 28 | libxml2-dev \ 29 | libzip-dev \ 30 | openldap-dev \ 31 | pcre-dev \ 32 | postgresql-dev \ 33 | imagemagick-dev \ 34 | ; \ 35 | \ 36 | docker-php-ext-configure gd --with-freetype-dir=/usr --with-png-dir=/usr --with-jpeg-dir=/usr; \ 37 | docker-php-ext-configure ldap; \ 38 | docker-php-ext-install \ 39 | exif \ 40 | gd \ 41 | intl \ 42 | ldap \ 43 | opcache \ 44 | pcntl \ 45 | pdo_mysql \ 46 | pdo_pgsql \ 47 | zip \ 48 | ; \ 49 | \ 50 | # pecl will claim success even if one install fails, so we need to perform each install separately 51 | pecl install APCu-5.1.17; \ 52 | pecl install memcached-3.1.3; \ 53 | pecl install redis-4.3.0; \ 54 | pecl install imagick-3.4.4; \ 55 | \ 56 | docker-php-ext-enable \ 57 | apcu \ 58 | memcached \ 59 | redis \ 60 | imagick \ 61 | ; \ 62 | \ 63 | runDeps="$( \ 64 | scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \ 65 | | tr ',' '\n' \ 66 | | sort -u \ 67 | | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ 68 | )"; \ 69 | apk add --virtual .nextcloud-phpext-rundeps $runDeps; \ 70 | apk del .build-deps 71 | 72 | # set recommended PHP.ini settings 73 | # see https://docs.nextcloud.com/server/12/admin_manual/configuration_server/server_tuning.html#enable-php-opcache 74 | RUN { \ 75 | echo 'opcache.enable=1'; \ 76 | echo 'opcache.enable_cli=1'; \ 77 | echo 'opcache.interned_strings_buffer=8'; \ 78 | echo 'opcache.max_accelerated_files=10000'; \ 79 | echo 'opcache.memory_consumption=128'; \ 80 | echo 'opcache.save_comments=1'; \ 81 | echo 'opcache.revalidate_freq=1'; \ 82 | } > /usr/local/etc/php/conf.d/opcache-recommended.ini; \ 83 | \ 84 | echo 'apc.enable_cli=1' >> /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini; \ 85 | \ 86 | echo 'memory_limit=512M' > /usr/local/etc/php/conf.d/memory-limit.ini; \ 87 | \ 88 | mkdir /var/www/data; \ 89 | chown -R www-data:root /var/www; \ 90 | chmod -R g=u /var/www 91 | 92 | VOLUME /var/www/html 93 | 94 | 95 | ENV NEXTCLOUD_VERSION 16.0.1 96 | 97 | RUN set -ex; \ 98 | apk add --no-cache --virtual .fetch-deps \ 99 | bzip2 \ 100 | gnupg \ 101 | ; \ 102 | \ 103 | curl -fsSL -o nextcloud.tar.bz2 \ 104 | "https://download.nextcloud.com/server/releases/nextcloud-${NEXTCLOUD_VERSION}.tar.bz2"; \ 105 | curl -fsSL -o nextcloud.tar.bz2.asc \ 106 | "https://download.nextcloud.com/server/releases/nextcloud-${NEXTCLOUD_VERSION}.tar.bz2.asc"; \ 107 | export GNUPGHOME="$(mktemp -d)"; \ 108 | # gpg key from https://nextcloud.com/nextcloud.asc 109 | gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys 28806A878AE423A28372792ED75899B9A724937A; \ 110 | gpg --batch --verify nextcloud.tar.bz2.asc nextcloud.tar.bz2; \ 111 | tar -xjf nextcloud.tar.bz2 -C /usr/src/; \ 112 | gpgconf --kill all; \ 113 | rm -r "$GNUPGHOME" nextcloud.tar.bz2.asc nextcloud.tar.bz2; \ 114 | rm -rf /usr/src/nextcloud/updater; \ 115 | mkdir -p /usr/src/nextcloud/data; \ 116 | mkdir -p /usr/src/nextcloud/custom_apps; \ 117 | chmod +x /usr/src/nextcloud/occ; \ 118 | apk del .fetch-deps 119 | 120 | COPY *.sh upgrade.exclude / 121 | COPY config/* /usr/src/nextcloud/config/ 122 | 123 | ENTRYPOINT ["/entrypoint.sh"] 124 | CMD ["php-fpm"] 125 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/nextcloud_build/config/apcu.config.php: -------------------------------------------------------------------------------- 1 | '\OC\Memcache\APCu', 4 | ); 5 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/nextcloud_build/config/apps.config.php: -------------------------------------------------------------------------------- 1 | array ( 4 | 0 => array ( 5 | "path" => OC::$SERVERROOT."/apps", 6 | "url" => "/apps", 7 | "writable" => false, 8 | ), 9 | 1 => array ( 10 | "path" => OC::$SERVERROOT."/custom_apps", 11 | "url" => "/custom_apps", 12 | "writable" => true, 13 | ), 14 | ), 15 | ); 16 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/nextcloud_build/config/autoconfig.php: -------------------------------------------------------------------------------- 1 | '\OC\Memcache\Redis', 5 | 'memcache.locking' => '\OC\Memcache\Redis', 6 | 'redis' => array( 7 | 'host' => getenv('REDIS_HOST'), 8 | 'port' => getenv('REDIS_HOST_PORT') ?: 6379, 9 | ), 10 | ); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/nextcloud_build/config/smtp.config.php: -------------------------------------------------------------------------------- 1 | 'smtp', 5 | 'mail_smtphost' => getenv('SMTP_HOST'), 6 | 'mail_smtpport' => getenv('SMTP_PORT') ?: (getenv('SMTP_SECURE') ? 465 : 25), 7 | 'mail_smtpsecure' => getenv('SMTP_SECURE') ?: '', 8 | 'mail_smtpauth' => getenv('SMTP_NAME') && getenv('SMTP_PASSWORD'), 9 | 'mail_smtpauthtype' => getenv('SMTP_AUTHTYPE') ?: 'LOGIN', 10 | 'mail_smtpname' => getenv('SMTP_NAME') ?: '', 11 | 'mail_smtppassword' => getenv('SMTP_PASSWORD') ?: '', 12 | 'mail_from_address' => getenv('MAIL_FROM_ADDRESS'), 13 | 'mail_domain' => getenv('MAIL_DOMAIN'), 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/nextcloud_build/cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | exec busybox crond -f -l 0 -L /dev/stdout 5 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/nextcloud_build/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | # version_greater A B returns whether A > B 5 | version_greater() { 6 | [ "$(printf '%s\n' "$@" | sort -t '.' -n -k1,1 -k2,2 -k3,3 -k4,4 | head -n 1)" != "$1" ] 7 | } 8 | 9 | # return true if specified directory is empty 10 | directory_empty() { 11 | [ -z "$(ls -A "$1/")" ] 12 | } 13 | 14 | run_as() { 15 | if [ "$(id -u)" = 0 ]; then 16 | su -p www-data -s /bin/sh -c "$1" 17 | else 18 | sh -c "$1" 19 | fi 20 | } 21 | 22 | if expr "$1" : "apache" 1>/dev/null || [ "$1" = "php-fpm" ] || [ "${NEXTCLOUD_UPDATE:-0}" -eq 1 ]; then 23 | if [ -n "${REDIS_HOST+x}" ]; then 24 | 25 | echo "Configuring Redis as session handler" 26 | { 27 | echo 'session.save_handler = redis' 28 | echo "session.save_path = \"tcp://${REDIS_HOST}:${REDIS_HOST_PORT:=6379}\"" 29 | } > /usr/local/etc/php/conf.d/redis-session.ini 30 | fi 31 | 32 | installed_version="0.0.0.0" 33 | if [ -f /var/www/html/version.php ]; then 34 | # shellcheck disable=SC2016 35 | installed_version="$(php -r 'require "/var/www/html/version.php"; echo implode(".", $OC_Version);')" 36 | fi 37 | # shellcheck disable=SC2016 38 | image_version="$(php -r 'require "/usr/src/nextcloud/version.php"; echo implode(".", $OC_Version);')" 39 | 40 | if version_greater "$installed_version" "$image_version"; then 41 | echo "Can't start Nextcloud because the version of the data ($installed_version) is higher than the docker image version ($image_version) and downgrading is not supported. Are you sure you have pulled the newest image version?" 42 | exit 1 43 | fi 44 | 45 | if version_greater "$image_version" "$installed_version"; then 46 | echo "Initializing nextcloud $image_version ..." 47 | if [ "$installed_version" != "0.0.0.0" ]; then 48 | echo "Upgrading nextcloud from $installed_version ..." 49 | run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before 50 | fi 51 | if [ "$(id -u)" = 0 ]; then 52 | rsync_options="-rlDog --chown www-data:root" 53 | else 54 | rsync_options="-rlD" 55 | fi 56 | rsync $rsync_options --delete --exclude-from=/upgrade.exclude /usr/src/nextcloud/ /var/www/html/ 57 | 58 | for dir in config data custom_apps themes; do 59 | if [ ! -d "/var/www/html/$dir" ] || directory_empty "/var/www/html/$dir"; then 60 | rsync $rsync_options --include "/$dir/" --exclude '/*' /usr/src/nextcloud/ /var/www/html/ 61 | fi 62 | done 63 | rsync $rsync_options --include '/version.php' --exclude '/*' /usr/src/nextcloud/ /var/www/html/ 64 | echo "Initializing finished" 65 | 66 | #install 67 | if [ "$installed_version" = "0.0.0.0" ]; then 68 | echo "New nextcloud instance" 69 | 70 | if [ -n "${NEXTCLOUD_ADMIN_USER+x}" ] && [ -n "${NEXTCLOUD_ADMIN_PASSWORD+x}" ]; then 71 | # shellcheck disable=SC2016 72 | install_options='-n --admin-user "$NEXTCLOUD_ADMIN_USER" --admin-pass "$NEXTCLOUD_ADMIN_PASSWORD"' 73 | if [ -n "${NEXTCLOUD_TABLE_PREFIX+x}" ]; then 74 | # shellcheck disable=SC2016 75 | install_options=$install_options' --database-table-prefix "$NEXTCLOUD_TABLE_PREFIX"' 76 | else 77 | install_options=$install_options' --database-table-prefix ""' 78 | fi 79 | if [ -n "${NEXTCLOUD_DATA_DIR+x}" ]; then 80 | # shellcheck disable=SC2016 81 | install_options=$install_options' --data-dir "$NEXTCLOUD_DATA_DIR"' 82 | fi 83 | 84 | install=false 85 | if [ -n "${SQLITE_DATABASE+x}" ]; then 86 | echo "Installing with SQLite database" 87 | # shellcheck disable=SC2016 88 | install_options=$install_options' --database-name "$SQLITE_DATABASE"' 89 | install=true 90 | elif [ -n "${MYSQL_DATABASE+x}" ] && [ -n "${MYSQL_USER+x}" ] && [ -n "${MYSQL_PASSWORD+x}" ] && [ -n "${MYSQL_HOST+x}" ]; then 91 | echo "Installing with MySQL database" 92 | # shellcheck disable=SC2016 93 | install_options=$install_options' --database mysql --database-name "$MYSQL_DATABASE" --database-user "$MYSQL_USER" --database-pass "$MYSQL_PASSWORD" --database-host "$MYSQL_HOST"' 94 | install=true 95 | elif [ -n "${POSTGRES_DB+x}" ] && [ -n "${POSTGRES_USER+x}" ] && [ -n "${POSTGRES_PASSWORD+x}" ] && [ -n "${POSTGRES_HOST+x}" ]; then 96 | echo "Installing with PostgreSQL database" 97 | # shellcheck disable=SC2016 98 | install_options=$install_options' --database pgsql --database-name "$POSTGRES_DB" --database-user "$POSTGRES_USER" --database-pass "$POSTGRES_PASSWORD" --database-host "$POSTGRES_HOST"' 99 | install=true 100 | fi 101 | 102 | if [ "$install" = true ]; then 103 | echo "starting nextcloud installation" 104 | max_retries=10 105 | try=0 106 | until run_as "php /var/www/html/occ maintenance:install $install_options" || [ "$try" -gt "$max_retries" ] 107 | do 108 | echo "retrying install..." 109 | try=$((try+1)) 110 | sleep 3s 111 | done 112 | if [ "$try" -gt "$max_retries" ]; then 113 | echo "installing of nextcloud failed!" 114 | exit 1 115 | fi 116 | if [ -n "${NEXTCLOUD_TRUSTED_DOMAINS+x}" ]; then 117 | echo "setting trusted domains…" 118 | NC_TRUSTED_DOMAIN_IDX=1 119 | for DOMAIN in $NEXTCLOUD_TRUSTED_DOMAINS ; do 120 | DOMAIN=$(echo "$DOMAIN" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') 121 | run_as "php /var/www/html/occ config:system:set trusted_domains $NC_TRUSTED_DOMAIN_IDX --value=$DOMAIN" 122 | NC_TRUSTED_DOMAIN_IDX=$(($NC_TRUSTED_DOMAIN_IDX+1)) 123 | done 124 | fi 125 | else 126 | echo "running web-based installer on first connect!" 127 | fi 128 | fi 129 | #upgrade 130 | else 131 | run_as 'php /var/www/html/occ upgrade' 132 | 133 | run_as 'php /var/www/html/occ app:list' | sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_after 134 | echo "The following apps have been disabled:" 135 | diff /tmp/list_before /tmp/list_after | grep '<' | cut -d- -f2 | cut -d: -f1 136 | rm -f /tmp/list_before /tmp/list_after 137 | 138 | fi 139 | fi 140 | fi 141 | 142 | exec "$@" 143 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/nextcloud_build/upgrade.exclude: -------------------------------------------------------------------------------- 1 | /config/ 2 | /data/ 3 | /custom_apps/ 4 | /themes/ 5 | /version.php 6 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-nextcloud/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-nyancat/README.md: -------------------------------------------------------------------------------- 1 | This is a telnet onion server with Nyancat. 2 | https://hub.docker.com/r/ddhhz/nyancat-server/ 3 | -------------------------------------------------------------------------------- /tor-fied-nyancat/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | tor: 4 | build: tor_build/ 5 | links: 6 | - nyan 7 | restart: always 8 | # Keep keys in volumes 9 | volumes: 10 | - ./tor:/var/lib/tor/hidden_service 11 | environment: 12 | # Set mapping ports 13 | NYAN_PORTS: "23:23" 14 | 15 | nyan: 16 | build: nyan_build/ 17 | restart: always 18 | -------------------------------------------------------------------------------- /tor-fied-nyancat/nyan_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | LABEL \ 3 | maintainer="Wei He " \ 4 | verion="1.0" \ 5 | description="Nyancat Telnet Server" 6 | 7 | RUN \ 8 | apk upgrade --update && \ 9 | apk add g++ make git autoconf automake && \ 10 | 11 | cd /tmp && git clone https://github.com/klange/nyancat.git && \ 12 | cd /tmp/nyancat && make && \ 13 | cp ./src/nyancat /usr/local/bin/ && \ 14 | cd / && rm -rf /tmp/nyancat && \ 15 | 16 | #cd /tmp && git clone https://github.com/ddhhz/onenetd.git && \ 17 | #cd /tmp/onenetd && autoreconf -vfi && ./configure && make && \ 18 | #cp ./onenetd /usr/local/bin && \ 19 | #cd / && rm -rf /tmp/onenetd && \ 20 | 21 | apk del --purge g++ make git autoconf automake 22 | 23 | EXPOSE 23 24 | 25 | RUN /usr/local/bin/nyancat -t 26 | -------------------------------------------------------------------------------- /tor-fied-nyancat/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-nyancat/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-nyancat/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-nyancat/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-nyancat/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-nyancat/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-nyancat/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-owncloud/README.md: -------------------------------------------------------------------------------- 1 | # tor-fied-wordpress 2 | ## Intro 3 | 4 | This is a docker-compose script for creating a simple wordpress hidden service onion. 5 | 6 | ### Special thanks to [cmehay](https://github.com/cmehay/docker-docker-tor-hidden-service) and to the [Wordpress project](https://hub.docker.com/_/wordpress/) for their projects which allowed me to build this one. 7 | 8 | ### About the script: 9 | In truth, very little was done apart from copying and pasting from the two above mentioned projects into a new docker-compose file and tailoring it a little to make the two projects works together. 10 | 11 | #### Variables 12 | 13 | Volumes: By default, docker-compose will create a ~/.keys directory with the hostname and private key. You can change the local directory whatevery you want 14 | 15 | Passwords: Change the mysql root and user passwords to something other than the default passwords. Make sure that MYSQL_PASSWORD and WORDPRESS_DB_PASSWORD are the same password as they are referring to the same thing. 16 | 17 | ``` 18 | $ docker-compose up -d 19 | ``` 20 | #### What's my .onion url? 21 | 22 | Your new .onion hostname will be in ~/.keys/wordpress/hostname or you can run the following command: 23 | 24 | ``` 25 | $ docker exec -ti torfiedwordpress_tor_1 onions 26 | ``` 27 | 28 | #### Other applications 29 | 30 | I've used this process to create several other hidden service applications such as tomcat, jboss, as well as more commonplace webservers like apache and nginx. 31 | -------------------------------------------------------------------------------- /tor-fied-owncloud/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | tor: 4 | image: jsevans/tor-hidden-service:latest 5 | links: 6 | - owncloud 7 | restart: always 8 | # Keep keys in volumes 9 | volumes: 10 | - ./tor:/var/lib/tor/hidden_service 11 | environment: 12 | # Set mapping ports 13 | OWNCLOUD_PORTS: "80:80" 14 | db: 15 | image: mariadb 16 | restart: always 17 | environment: 18 | MYSQL_ROOT_PASSWORD: rootpass 19 | MYSQL_DATABASE: owncloud 20 | MYSQL_USER: cloudadmin 21 | MYSQL_PASSWORD: wordpress123 22 | volumes: 23 | - ./mysql:/var/lib/mysql 24 | 25 | owncloud: 26 | image: owncloud:9 27 | restart: always 28 | ports: 29 | - 8080:80 30 | -------------------------------------------------------------------------------- /tor-fied-owncloud/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-owncloud/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-owncloud/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-owncloud/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-owncloud/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-owncloud/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-owncloud/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-paperwork/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:edge 2 | 3 | MAINTAINER Conor Anderson 4 | 5 | RUN apk add --update --no-cache \ 6 | bash \ 7 | curl \ 8 | git \ 9 | lighttpd \ 10 | nodejs \ 11 | php5 \ 12 | php5-cgi \ 13 | php5-ctype \ 14 | php5-curl \ 15 | php5-dom \ 16 | php5-gd \ 17 | php5-iconv \ 18 | php5-json \ 19 | php5-mcrypt \ 20 | php5-openssl \ 21 | php5-pdo \ 22 | php5-pdo_mysql \ 23 | php5-phar 24 | 25 | RUN git clone --depth 1 https://github.com/twostairs/paperwork.git &&\ 26 | mv paperwork/frontend /app &&\ 27 | rm -rf paperwork 28 | 29 | RUN curl -sSL https://getcomposer.org/installer | php &&\ 30 | mv composer.phar /usr/local/bin/composer 31 | 32 | WORKDIR /app 33 | 34 | RUN find ./app/storage -type d -print0 | xargs -0 chmod 0755 &&\ 35 | find ./app/storage -type f -print0 | xargs -0 chmod 0644 &&\ 36 | composer install --prefer-source --no-interaction &&\ 37 | npm update &&\ 38 | npm install &&\ 39 | npm install -g gulp bower &&\ 40 | bower --allow-root install &&\ 41 | gulp &&\ 42 | chown -R lighttpd:lighttpd /app &&\ 43 | chmod +x /app/docker-runner.sh 44 | 45 | RUN sed -i 's/return $app;//' /app/bootstrap/start.php 46 | RUN echo '$env = $app->detectEnvironment(function() { return "development"; }); return $app;' >> /app/bootstrap/start.php 47 | 48 | RUN mkdir -p /run/lighttpd && \ 49 | chown -R lighttpd:lighttpd /run/lighttpd/ 50 | 51 | COPY paperwork.ico /app/public/favicon.ico 52 | 53 | COPY lighttpd.conf /etc/lighttpd/ 54 | 55 | VOLUME ["/app/app/storage/"] 56 | 57 | ENV PAPERWORK_URL=paperwork.example.com 58 | 59 | RUN echo 'if [ $(grep -c "paperwork.example.com" /app/app/config/paperwork.php) == "1" ]; then sed -i "s/paperwork.example.com/$PAPERWORK_URL/g" /app/app/config/paperwork.php; fi' > /run.sh &&\ 60 | echo "lighttpd -f /etc/lighttpd/lighttpd.conf -D" >> /run.sh &&\ 61 | chmod +x /run.sh 62 | 63 | CMD ["/app/docker-runner.sh"] 64 | 65 | EXPOSE 80 66 | 67 | -------------------------------------------------------------------------------- /tor-fied-paperwork/README.md: -------------------------------------------------------------------------------- 1 | Currently not working. I need a new upstream image. 2 | -------------------------------------------------------------------------------- /tor-fied-paperwork/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | services: 4 | tor: 5 | image: jsevans/tor-hidden-service:latest 6 | links: 7 | - paperwork 8 | restart: always 9 | volumes: 10 | - ./keys/:/var/lib/tor/hidden_service/ 11 | environment: 12 | # Set mapping ports 13 | PAPERWORK_PORTS: "80:80" 14 | 15 | paperwork: 16 | image: conoria/paperwork 17 | links: 18 | - paperwork-db:paperwork-db 19 | 20 | paperwork-db: 21 | image: mariadb 22 | restart: always 23 | environment: 24 | MYSQL_ROOT_PASSWORD: rootpass 25 | MYSQL_DATABASE: wordpress 26 | MYSQL_USER: wordpress 27 | MYSQL_PASSWORD: wordpress123 28 | volumes: 29 | - ./mysql:/var/lib/mysql 30 | 31 | -------------------------------------------------------------------------------- /tor-fied-paperwork/lighttpd.conf: -------------------------------------------------------------------------------- 1 | 2 | server.modules = ("mod_rewrite", "mod_access", "mod_accesslog") 3 | 4 | include "mime-types.conf" 5 | include "mod_fastcgi.conf" 6 | 7 | server.username = "lighttpd" 8 | server.groupname = "lighttpd" 9 | 10 | server.document-root = "/app/public" 11 | server.pid-file = "/var/run/lighttpd.pid" 12 | 13 | server.indexfiles = ("index.php", "index.html", "index.htm", "default.htm") 14 | 15 | static-file.exclude-extensions = (".php") 16 | 17 | url.rewrite-if-not-file = ( 18 | "^/[^\?]*(\?.*)?$" => "index.php/$1" 19 | ) 20 | -------------------------------------------------------------------------------- /tor-fied-paperwork/paperwork.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tgeek77/compose-scripts-tor/db856081dbf13a187dd9e8abbcda712d7578b524/tor-fied-paperwork/paperwork.ico -------------------------------------------------------------------------------- /tor-fied-paperwork/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-paperwork/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-paperwork/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-paperwork/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-paperwork/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-paperwork/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-paperwork/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-starwars/README.md: -------------------------------------------------------------------------------- 1 | This is rohan's telnet server with Ascii Star Wars playing but as an onion server running on port 1977. 2 | https://hub.docker.com/r/rohan/ascii-telnet-server/ 3 | -------------------------------------------------------------------------------- /tor-fied-starwars/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | tor: 4 | build: tor_build/ 5 | links: 6 | - starwars 7 | restart: always 8 | # Keep keys in volumes 9 | volumes: 10 | - .tor:/var/lib/tor/hidden_service 11 | environment: 12 | # Set mapping ports 13 | STARWARS_PORTS: "1977:23" 14 | 15 | starwars: 16 | build: starwars_build/ 17 | restart: always 18 | -------------------------------------------------------------------------------- /tor-fied-starwars/starwars_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | MAINTAINER Rohan Singh "rohan@washington.edu" 3 | 4 | RUN apk update && apk add python 5 | 6 | ADD ascii-telnet-server.py /root/ 7 | ADD sw1.txt /root/ 8 | 9 | EXPOSE 23 10 | 11 | ENTRYPOINT ["python", "/root/ascii-telnet-server.py"] 12 | CMD ["-f", "/root/sw1.txt"] 13 | -------------------------------------------------------------------------------- /tor-fied-starwars/starwars_build/README.md: -------------------------------------------------------------------------------- 1 | ASCII art movie Telnet player 2 | ============================= 3 | 4 | Can stream an ~20 minutes ASCII movie via Telnet emulation 5 | as stand alone server or via xinetd daemon. 6 | 7 | Tested with Python 2.3, Python 2.5, Python 2.7 8 | 9 | Original art work : Simon Jansen [http://www.asciimation.co.nz/](http://www.asciimation.co.nz/) 10 | Telnetification & Player coding : Martin W. Kirst 11 | 12 | Command line parameters 13 | ----------------------- 14 | 15 | See program output: 16 | 17 | $ python ascii-telnet-server.py --help 18 | Usage: ascii-telnet-server.py [options] 19 | Options: 20 | -h, --help show this help message and exit 21 | --standalone Run as stand alone multi threaded TCP server (default) 22 | --stdout Run with STDIN and STDOUT, for example in XINETD 23 | instead of stand alone TCP server. Use with python 24 | option '-u' for unbuffered STDIN STDOUT communication 25 | -f FILE, --file=FILE Text file containing the ASCII movie 26 | -i INTERFACE, --interface=INTERFACE 27 | Bind to this interface (default '0.0.0.0', all 28 | interfaces) 29 | -p PORT, --port=PORT Bind to this port (default 23, Telnet) 30 | -v, --verbose Verbose (default for TCP server) 31 | -q, --quiet Quiet! (default for STDIN STDOUT server) 32 | 33 | 34 | Run as stand alone server 35 | ------------------------- 36 | 37 | Simple call this Python script by using the sample movie file: 38 | 39 | $> python ascii-telnet-server.py --standalone -f sw1.txt 40 | Running TCP server on 0.0.0.0:23 41 | Playing movie sw1.txt 42 | 43 | 44 | Run as xinetd program 45 | --------------------- 46 | 47 | place this configuration into `/etc/xinetd.d/telnet`: 48 | 49 | # default: on 50 | # description: An telnet service playing an ASCII movie, Star Wars Episode 4 51 | service telnet 52 | { 53 | disable = no 54 | socket_type = stream 55 | protocol = tcp 56 | port = 23 57 | user = root 58 | wait = no 59 | instances = 10 60 | 61 | log_type = FILE /var/log/asciiplayer 62 | log_on_success += PID HOST DURATION 63 | log_on_failure = HOST 64 | server = /usr/bin/python 65 | server_args = -u -OO /opt/asciiplayer/ascii-telnet-server.py -f /opt/asciiplayer/sw1.txt --stdout 66 | } 67 | 68 | -------------------------------------------------------------------------------- /tor-fied-starwars/starwars_build/sw1.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tgeek77/compose-scripts-tor/db856081dbf13a187dd9e8abbcda712d7578b524/tor-fied-starwars/starwars_build/sw1.txt -------------------------------------------------------------------------------- /tor-fied-starwars/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-starwars/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-starwars/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-starwars/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-starwars/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-starwars/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-starwars/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-tomcat/README.md: -------------------------------------------------------------------------------- 1 | # tor-fied-ghost 2 | ## Intro 3 | 4 | This is a docker-compose script for creating a simple Ghost installation. 5 | 6 | ### Special thanks to: 7 | 8 | [cmehay](https://github.com/cmehay/docker-docker-tor-hidden-service) 9 | [ghost](https://hub.docker.com/_/ghost/) 10 | 11 | for their projects which allowed me to build this one. 12 | 13 | ### About the script: 14 | In truth, very little was done apart from copying and pasting from the two above mentioned projects into a new docker-compose file and tailoring it a little to make the two projects works together. 15 | 16 | #### Variables 17 | 18 | Volumes: By default, docker-compose will create a ~/.keys directory with the hostname and private key. You can change the local directory whatevery you want 19 | 20 | ``` 21 | $ docker-compose up -d 22 | ``` 23 | #### What's my .onion url? 24 | 25 | Your new .onion hostname will be in ~/.keys/ghost/hostname or you can run the following command: 26 | 27 | ``` 28 | $ docker exec -ti torfiedghost_tor_1 onions 29 | ``` 30 | 31 | ### Problems 32 | * email isn't working -- see http://support.ghost.org/mail for more help with that. 33 | 34 | -------------------------------------------------------------------------------- /tor-fied-tomcat/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | services: 4 | tor: 5 | image: jsevans/tor-hidden-service:latest 6 | links: 7 | - tomcat 8 | restart: always 9 | # Keep keys in volumes 10 | volumes: 11 | - "~/.keys/:/var/lib/tor/hidden_service/" 12 | environment: 13 | # Set mapping ports 14 | TOMCAT_PORTS: "80:8080" 15 | 16 | tomcat: 17 | image: jsevans/tomcat-opensuse 18 | restart: always 19 | -------------------------------------------------------------------------------- /tor-fied-tomcat/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-tomcat/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-tomcat/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-tomcat/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-tomcat/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-tomcat/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-tomcat/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-web/README.md: -------------------------------------------------------------------------------- 1 | This is a plain environment meant for one thing: Build plain static websites with little or no javascript. 2 | 3 | The "apache" image is based on [OpenSUSE Tumbleweed](https://en.opensuse.org/Portal:Tumbleweed). Tumbleweed is a "cutting edge" rolling distribution. Think Arch Linux but more mature and user-friendly. 4 | 5 | The image created by the "web_build" Dockerfile will create a rather huge image. It is designed to allow you to create websites using the markup language of your choice. You can either use Daps with Asciidoc, Sphinx with reStructuredText, or Pandoc with Markdown. 6 | 7 | To log into the container and use the tools, run: `docker exec -it torfiedweb_apache_1 bash`. 8 | 9 | To fetch your Tor onion service url, run `docker exec torfiedweb_tor_1 v3onions` 10 | 11 | The apache container does not have any logs running for apache. This is to keep any visitors safe in case your website is seized or hacked. 12 | 13 | What is [Tor](https://2019.www.torproject.org/about/overview.html.en)? 14 | 15 | For more information on [Daps](https://opensuse.github.io/daps/doc/daps-asciidoc.html) and [Asciidoc](http://asciidoc.org/). 16 | 17 | For more information on [Sphinx](https://www.sphinx-doc.org/en/master/) and [reStructuredText](http://docutils.sourceforge.net/rst.html). 18 | 19 | For more information on [Pandoc](https://pandoc.org/) and [Markdown](https://www.markdownguide.org/) 20 | -------------------------------------------------------------------------------- /tor-fied-web/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | services: 4 | tor: 5 | build: tor_build/ 6 | links: 7 | - apache 8 | volumes: 9 | - ".tor/:/var/lib/tor/hidden_service/" 10 | environment: 11 | APACHE_PORTS: "80:80" 12 | apache: 13 | build: web_build/ 14 | restart: always 15 | volumes: 16 | - "~/www/:/srv/www/htdocs/" 17 | - "~/work/:/root/" 18 | -------------------------------------------------------------------------------- /tor-fied-web/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-web/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-web/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-web/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-web/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-web/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-web/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | -------------------------------------------------------------------------------- /tor-fied-web/web_build/000-default.conf: -------------------------------------------------------------------------------- 1 | 2 | # The ServerName directive sets the request scheme, hostname and port that 3 | # the server uses to identify itself. This is used when creating 4 | # redirection URLs. In the context of virtual hosts, the ServerName 5 | # specifies what hostname must appear in the request's Host: header to 6 | # match this virtual host. For the default virtual host (this file) this 7 | # value is not decisive as it is used as a last resort host regardless. 8 | # However, you must set it for any further virtual host explicitly. 9 | #ServerName www.example.com 10 | 11 | ServerAdmin webmaster@localhost 12 | DocumentRoot /var/www/html 13 | 14 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, 15 | # error, crit, alert, emerg. 16 | # It is also possible to configure the loglevel for particular 17 | # modules, e.g. 18 | #LogLevel info ssl:warn 19 | 20 | ErrorLog ${APACHE_LOG_DIR}/error.log 21 | #CustomLog ${APACHE_LOG_DIR}/access.log combined 22 | 23 | #CustomLog /dev/null 24 | 25 | # For most configuration files from conf-available/, which are 26 | # enabled or disabled at a global level, it is possible to 27 | # include a line for only one particular virtual host. For example the 28 | # following line enables the CGI configuration for this host only 29 | # after it has been globally disabled with "a2disconf". 30 | #Include conf-available/serve-cgi-bin.conf 31 | 32 | 33 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 34 | -------------------------------------------------------------------------------- /tor-fied-web/web_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM opensuse/tumbleweed 2 | 3 | # install base packages 4 | RUN zypper ref && zypper -n install apache2 git 5 | RUN zypper -n install daps ruby2.6-rubygem-asciidoctor 6 | RUN zypper -n install python3-Sphinx python3-restructuredtext_lint 7 | RUN zypper -n install pandoc 8 | 9 | COPY global.conf /etc/apache2/ 10 | COPY global.conf /etc/apache2/sysconfig.d/ 11 | CMD /usr/sbin/apache2ctl -D FOREGROUND 12 | 13 | VOLUME ["/srv/www/htdocs"] 14 | VOLUME ["/root"] 15 | 16 | 17 | EXPOSE 80 18 | -------------------------------------------------------------------------------- /tor-fied-web/web_build/default-server.conf: -------------------------------------------------------------------------------- 1 | # 2 | # Global configuration that will be applicable for all virtual hosts, unless 3 | # deleted here, or overriden elswhere. 4 | # 5 | 6 | DocumentRoot "/srv/www/htdocs" 7 | 8 | # 9 | # Configure the DocumentRoot 10 | # 11 | 12 | # Possible values for the Options directive are "None", "All", 13 | # or any combination of: 14 | # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews 15 | # 16 | # Note that "MultiViews" must be named *explicitly* --- "Options All" 17 | # doesn't give it to you. 18 | # 19 | # The Options directive is both complicated and important. Please see 20 | # http://httpd.apache.org/docs/2.4/mod/core.html#options 21 | # for more information. 22 | # NOTE: For directories where RewriteRule is used, FollowSymLinks 23 | # or SymLinksIfOwnerMatch needs to be set in Options directive. 24 | Options None 25 | # AllowOverride controls what directives may be placed in .htaccess files. 26 | # It can be "All", "None", or any combination of the keywords: 27 | # Options FileInfo AuthConfig Limit 28 | AllowOverride None 29 | # Controls who can get stuff from this server. 30 | 31 | Require all granted 32 | 33 | 34 | Order allow,deny 35 | Allow from all 36 | 37 | 38 | 39 | # Aliases: aliases can be added as needed (with no limit). The format is 40 | # Alias fakename realname 41 | # 42 | # Note that if you include a trailing / on fakename then the server will 43 | # require it to be present in the URL. So "/icons" isn't aliased in this 44 | # example, only "/icons/". If the fakename is slash-terminated, then the 45 | # realname must also be slash terminated, and if the fakename omits the 46 | # trailing slash, the realname must also omit it. 47 | # 48 | # We include the /icons/ alias for FancyIndexed directory listings. If you 49 | # do not use FancyIndexing, you may comment this out. 50 | # 51 | Alias /icons/ "/usr/share/apache2/icons/" 52 | 53 | 54 | Options Indexes MultiViews 55 | AllowOverride None 56 | 57 | Require all granted 58 | 59 | 60 | Order allow,deny 61 | Allow from all 62 | 63 | 64 | 65 | # ScriptAlias: This controls which directories contain server scripts. 66 | # ScriptAliases are essentially the same as Aliases, except that 67 | # documents in the realname directory are treated as applications and 68 | # run by the server when requested rather than as documents sent to the client. 69 | # The same rules about trailing "/" apply to ScriptAlias directives as to 70 | # Alias. 71 | # 72 | ScriptAlias /cgi-bin/ "/srv/www/cgi-bin/" 73 | 74 | # "/srv/www/cgi-bin" should be changed to whatever your ScriptAliased 75 | # CGI directory exists, if you have that configured. 76 | # 77 | 78 | AllowOverride None 79 | Options +ExecCGI -Includes 80 | 81 | Require all granted 82 | 83 | 84 | Order allow,deny 85 | Allow from all 86 | 87 | 88 | 89 | # UserDir: The name of the directory that is appended onto a user's home 90 | # directory if a ~user request is received. 91 | # 92 | # To disable it, simply remove userdir from the list of modules in APACHE_MODULES 93 | # in /etc/sysconfig/apache2. 94 | # 95 | 96 | # Note that the name of the user directory ("public_html") cannot simply be 97 | # changed here, since it is a compile time setting. The apache package 98 | # would have to be rebuilt. You could work around by deleting 99 | # /usr/sbin/suexec, but then all scripts from the directories would be 100 | # executed with the UID of the webserver. 101 | UserDir public_html 102 | # The actual configuration of the directory is in 103 | # /etc/apache2/mod_userdir.conf. 104 | Include /etc/apache2/mod_userdir.conf 105 | # You can, however, change the ~ if you find it awkward, by mapping e.g. 106 | # http://www.example.com/users/karl-heinz/ --> /home/karl-heinz/public_html/ 107 | #AliasMatch ^/users/([a-zA-Z0-9-_.]*)/?(.*) /home/$1/public_html/$2 108 | 109 | 110 | 111 | # Include all *.conf files from /etc/apache2/conf.d/. 112 | # 113 | # This is mostly meant as a place for other RPM packages to drop in their 114 | # configuration snippet. 115 | # 116 | # You can comment this out here if you want those bits include only in a 117 | # certain virtual host, but not here. 118 | # 119 | IncludeOptional /etc/apache2/conf.d/*.conf 120 | 121 | # The manual... if it is installed ('?' means it won't complain) 122 | IncludeOptional /etc/apache2/conf.d/apache2-manual?conf 123 | 124 | -------------------------------------------------------------------------------- /tor-fied-web/web_build/global.conf: -------------------------------------------------------------------------------- 1 | ServerSignature off 2 | UseCanonicalName off 3 | ServerTokens ProductOnly 4 | #LogLevel warn 5 | CustomLog /dev/null combined 6 | 7 | -------------------------------------------------------------------------------- /tor-fied-wordpress/README.md: -------------------------------------------------------------------------------- 1 | # tor-fied-wordpress 2 | ## Intro 3 | 4 | This is a docker-compose script for creating a simple wordpress hidden service onion. 5 | 6 | ### Special thanks to [cmehay](https://github.com/cmehay/docker-docker-tor-hidden-service) and to the [Wordpress project](https://hub.docker.com/_/wordpress/) for their projects which allowed me to build this one. 7 | 8 | ### About the script: 9 | In truth, very little was done apart from copying and pasting from the two above mentioned projects into a new docker-compose file and tailoring it a little to make the two projects works together. 10 | 11 | #### Variables 12 | 13 | Volumes: By default, docker-compose will create a ~/.keys directory with the hostname and private key. You can change the local directory whatevery you want 14 | 15 | Passwords: Change the mysql root and user passwords to something other than the default passwords. Make sure that MYSQL_PASSWORD and WORDPRESS_DB_PASSWORD are the same password as they are referring to the same thing. 16 | 17 | ``` 18 | $ docker-compose up -d 19 | ``` 20 | #### What's my .onion url? 21 | 22 | Your new .onion hostname will be in ~/.keys/wordpress/hostname or you can run the following command: 23 | 24 | ``` 25 | $ docker exec -ti torfiedwordpress_tor_1 onions 26 | ``` 27 | 28 | #### Other applications 29 | 30 | I've used this process to create several other hidden service applications such as tomcat, jboss, as well as more commonplace webservers like apache and nginx. 31 | -------------------------------------------------------------------------------- /tor-fied-wordpress/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | tor: 4 | build: tor_build/ 5 | links: 6 | - wordpress 7 | restart: always 8 | # Keep keys in volumes 9 | volumes: 10 | - ./tor:/var/lib/tor/hidden_service 11 | environment: 12 | # Set mapping ports 13 | WORDPRESS_PORTS: "80:80" 14 | 15 | 16 | db: 17 | image: mariadb 18 | restart: always 19 | environment: 20 | MYSQL_ROOT_PASSWORD: rootpass 21 | MYSQL_DATABASE: wordpress 22 | MYSQL_USER: wordpress 23 | MYSQL_PASSWORD: wordpress123 24 | volumes: 25 | - ./mysql:/var/lib/mysql 26 | 27 | 28 | wordpress: 29 | depends_on: 30 | - db 31 | image: wordpress:latest 32 | links: 33 | - db 34 | restart: always 35 | environment: 36 | WORDPRESS_DB_HOST: db:3306 37 | WORDPRESS_DB_USER: wordpress 38 | WORDPRESS_DB_PASSWORD: wordpress123 39 | -------------------------------------------------------------------------------- /tor-fied-wordpress/tor_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | ENV HOME /var/lib/tor 4 | 5 | RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib zlib-dev && \ 6 | mkdir -p /usr/local/src/ && \ 7 | git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ 8 | cd /usr/local/src/tor && \ 9 | git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ 10 | head ReleaseNotes | grep version | awk -F"version" '{print $2}' | grep - | awk '{ print $1 }' > /version && \ 11 | ./autogen.sh && \ 12 | ./configure \ 13 | --disable-asciidoc \ 14 | --sysconfdir=/etc \ 15 | --disable-unittests && \ 16 | make && make install && \ 17 | cd .. && \ 18 | rm -rf tor && \ 19 | apk add --no-cache python3 python3-dev && \ 20 | python3 -m ensurepip && \ 21 | rm -r /usr/lib/python*/ensurepip && \ 22 | pip3 install --upgrade pip setuptools pycrypto && \ 23 | apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ 24 | apk add --no-cache libevent openssl 25 | 26 | RUN mkdir -p /etc/tor/ 27 | 28 | ADD assets/entrypoint-config.yml / 29 | ADD assets/onions /usr/local/src/onions 30 | ADD assets/torrc /var/local/tor/torrc.tpl 31 | ADD assets/v3onions /usr/bin/v3onions 32 | 33 | RUN chmod +x /usr/bin/v3onions 34 | RUN cd /usr/local/src/onions && python3 setup.py install 35 | 36 | RUN mkdir -p ${HOME}/.tor && \ 37 | addgroup -S -g 107 tor && \ 38 | adduser -S -G tor -u 104 -H -h ${HOME} tor 39 | 40 | VOLUME ["/var/lib/tor/hidden_service/"] 41 | 42 | ENTRYPOINT ["pyentrypoint"] 43 | 44 | CMD ["tor"] 45 | -------------------------------------------------------------------------------- /tor-fied-wordpress/tor_build/assets/entrypoint-config.yml: -------------------------------------------------------------------------------- 1 | command: tor 2 | 3 | user: tor 4 | group: tor 5 | 6 | secret_env: 7 | - '*_KEY' 8 | - '*_PORTS' 9 | - '*_SERVICE_NAME' 10 | 11 | pre_conf_commands: 12 | - onions --setup-hosts 13 | 14 | post_conf_commands: 15 | - chown -R tor:tor $HOME 16 | 17 | reload: 18 | files: 19 | - /etc/tor/torrc 20 | 21 | debug: false 22 | -------------------------------------------------------------------------------- /tor-fied-wordpress/tor_build/assets/onions/onions/Service.py: -------------------------------------------------------------------------------- 1 | 'This class define a service link' 2 | import logging 3 | import os 4 | import re 5 | from base64 import b32encode 6 | from hashlib import sha1 7 | 8 | from Crypto.PublicKey import RSA 9 | 10 | 11 | class ServicesGroup(object): 12 | 13 | name = None 14 | _priv_key = None 15 | _key_in_secrets = False 16 | 17 | hidden_service_dir = "/var/lib/tor/hidden_service/" 18 | 19 | def __init__(self, name=None, service=None, hidden_service_dir=None): 20 | 21 | name_regex = r'^[a-zA-Z0-9-_]+$' 22 | 23 | self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir 24 | if not name and not service: 25 | raise Exception( 26 | 'Init service group with a name or service at least' 27 | ) 28 | self.services = [] 29 | self.name = name or service.host 30 | if not re.match(name_regex, self.name): 31 | raise Exception( 32 | 'Group {name} has invalid name'.format(name=self.name) 33 | ) 34 | if service: 35 | self.add_service(service) 36 | 37 | self.load_key() 38 | if not self._priv_key: 39 | self.gen_key() 40 | 41 | def add_service(self, service): 42 | if service not in self.services: 43 | if self.get_service_by_host(service.host): 44 | raise Exception('Duplicate service name') 45 | self.services.append(service) 46 | 47 | def get_service_by_host(self, host): 48 | for service in self.services: 49 | if host == service.host: 50 | return service 51 | 52 | def add_key(self, key): 53 | if self._key_in_secrets: 54 | logging.warning('Secret key already set, overriding') 55 | self._priv_key = key 56 | self._key_in_secrets = False 57 | 58 | def __iter__(self): 59 | yield 'name', self.name 60 | yield 'onion', self.onion_url 61 | yield 'urls', list(self.urls) 62 | 63 | def __str__(self): 64 | return '{name}: {urls}'.format(name=self.name, 65 | urls=', '.join(self.urls)) 66 | 67 | @property 68 | def onion_url(self): 69 | "Get onion url from private key" 70 | 71 | # Convert private RSA to public DER 72 | priv = RSA.importKey(self._priv_key.strip()) 73 | der = priv.publickey().exportKey("DER") 74 | 75 | # hash key, keep first half of sha1, base32 encode 76 | onion = b32encode(sha1(der[22:]).digest()[:10]) 77 | 78 | return '{onion}.onion'.format(onion=onion.decode().lower()) 79 | 80 | @property 81 | def urls(self): 82 | for service in self.services: 83 | for ports in service.ports: 84 | yield '{onion}:{port}'.format(onion=self.onion_url, 85 | port=ports.port_from) 86 | 87 | def write_key(self, hidden_service_dir=None): 88 | 'Write key on disk and set tor service' 89 | if not hidden_service_dir: 90 | hidden_service_dir = self.hidden_service_dir 91 | serv_dir = os.path.join(hidden_service_dir, self.name) 92 | os.makedirs(serv_dir, exist_ok=True) 93 | os.chmod(serv_dir, 0o700) 94 | with open(os.path.join(serv_dir, 'private_key'), 'w') as f: 95 | f.write(self._priv_key) 96 | os.fchmod(f.fileno(), 0o600) 97 | with open(os.path.join(serv_dir, 'hostname'), 'w') as f: 98 | f.write(self.onion_url) 99 | 100 | def _load_key(self, key_file): 101 | if os.path.exists(key_file): 102 | with open(key_file, 'r') as f: 103 | key = f.read().encode() 104 | if not len(key): 105 | return 106 | try: 107 | rsa = RSA.importKey(key) 108 | self._priv_key = rsa.exportKey("PEM").decode() 109 | except BaseException: 110 | raise('Fail to load key for {name} services'.format( 111 | name=self.name 112 | )) 113 | 114 | def load_key(self): 115 | self.load_key_from_secrets() 116 | self.load_key_from_conf() 117 | 118 | def load_key_from_secrets(self): 119 | 'Load key from docker secret using service name' 120 | secret_file = os.path.join('/run/secrets', self.name) 121 | if not os.path.exists(secret_file): 122 | return 123 | try: 124 | self._load_key(secret_file) 125 | self._key_in_secrets = True 126 | except BaseException: 127 | logging.warning('Fail to load key from secret, ' 128 | 'check the key or secret name collision') 129 | 130 | def load_key_from_conf(self, hidden_service_dir=None): 131 | 'Load key from disk if exists' 132 | if not hidden_service_dir: 133 | hidden_service_dir = self.hidden_service_dir 134 | key_file = os.path.join(hidden_service_dir, 135 | self.name, 136 | 'private_key') 137 | self._load_key(key_file) 138 | 139 | def gen_key(self): 140 | 'Generate new 1024 bits RSA key for hidden service' 141 | self._priv_key = RSA.generate( 142 | bits=1024, 143 | ).exportKey("PEM").decode() 144 | 145 | 146 | class Ports: 147 | 148 | port_from = None 149 | dest = None 150 | 151 | def __init__(self, port_from, dest): 152 | self.port_from = int(port_from) 153 | self.dest = dest if dest.startswith('unix:') else int(dest) 154 | 155 | @property 156 | def is_socket(self): 157 | return self.dest and type(self.dest) is not int 158 | 159 | def __iter__(self): 160 | yield 'port_from', str(self.port_from) 161 | yield 'dest', str(self.dest) 162 | yield 'is_socket', self.is_socket 163 | 164 | 165 | class Service: 166 | 167 | def __init__(self, host): 168 | self.host = host 169 | self.ports = [] 170 | 171 | def add_ports(self, ports): 172 | p = [Ports(*sp.split(':', 1)) for sp in ports.split(',')] 173 | self.ports.extend(p) 174 | 175 | def __iter__(self): 176 | yield 'host', self.host 177 | yield 'ports', [dict(p) for p in self.ports] 178 | -------------------------------------------------------------------------------- /tor-fied-wordpress/tor_build/assets/onions/onions/__init__.py: -------------------------------------------------------------------------------- 1 | from .Onions import main 2 | from .Onions import Onions 3 | from .Service import Ports 4 | from .Service import Service 5 | from .Service import ServicesGroup 6 | -------------------------------------------------------------------------------- /tor-fied-wordpress/tor_build/assets/onions/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from setuptools import find_packages 4 | from setuptools import setup 5 | 6 | setup( 7 | name='onions', 8 | 9 | version='0.4.1', 10 | 11 | packages=find_packages(), 12 | 13 | author="Christophe Mehay", 14 | 15 | author_email="cmehay@nospam.student.42.fr", 16 | 17 | description="Display onion sites hosted", 18 | 19 | include_package_data=True, 20 | 21 | url='http://github.com/cmehay/docker-tor-hidden-service', 22 | 23 | classifiers=[ 24 | "Programming Language :: Python", 25 | "Development Status :: 1 - Planning", 26 | "License :: OSI Approved :: BSD License", 27 | "Natural Language :: English", 28 | "Operating System :: POSIX :: Linux", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.4", 31 | "Topic :: System :: Installation/Setup", 32 | ], 33 | 34 | install_requires=['pyentrypoint==0.5.1', 35 | 'Jinja2>=2.8', 36 | 'pycrypto', ], 37 | 38 | entry_points={ 39 | 'console_scripts': [ 40 | 'onions = onions:main', 41 | ], 42 | }, 43 | 44 | license="WTFPL", 45 | ) 46 | -------------------------------------------------------------------------------- /tor-fied-wordpress/tor_build/assets/torrc: -------------------------------------------------------------------------------- 1 | {% for service_group in services %} 2 | HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} 3 | {% for service in service_group.services %} 4 | {% for port in service.ports %} 5 | {% if port.is_socket %} 6 | HiddenServicePort {{port.port_from}} {{port.dest}} 7 | {% endif %} 8 | {% if not port.is_socket %} 9 | HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}} 10 | {% endif %} 11 | {% endfor %} 12 | {% endfor %} 13 | {% endfor %} 14 | 15 | {% if 'RELAY' in env %} 16 | ORPort 9001 17 | {% endif %} 18 | 19 | SocksPort 0 20 | 21 | # useless line for Jinja bug 22 | HiddenServiceVersion 3 23 | -------------------------------------------------------------------------------- /tor-fied-wordpress/tor_build/assets/v3onions: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Define Variables 4 | PORT=`onions | awk -F: '{ print $NF }'` 5 | ONION=`ls -l /var/lib/tor/hidden_service/*/hostname | cut -c58- && cat /var/lib/tor/hidden_service/*/hostname` 6 | 7 | #Displace v3address:port 8 | echo $ONION:$PORT 9 | --------------------------------------------------------------------------------