# wikiless Setup ![](0.png) In this tutorial we're going to check out how to install Wikiless, a privacy front-end for wikipedia. ## **Initial Setup** First git clone the repository [ nowhere.moe ] [ /dev/pts/2 ] [/srv] → git clone https://github.com/Metastem/wikiless Cloning into 'wikiless'... remote: Enumerating objects: 1080, done. remote: Counting objects: 100% (314/314), done. remote: Compressing objects: 100% (135/135), done. remote: Total 1080 (delta 216), reused 250 (delta 175), pack-reused 766 Receiving objects: 100% (1080/1080), 488.53 KiB | 8.14 MiB/s, done. Resolving deltas: 100% (598/598), done. [ nowhere.moe ] [ /dev/pts/2 ] [/srv] → cd wikiless run the docker files [ nowhere.moe ] [ /dev/pts/0 ] [/srv/wikiless] → git pull remote: Enumerating objects: 9, done. remote: Counting objects: 100% (9/9), done. remote: Compressing objects: 100% (6/6), done. remote: Total 6 (delta 4), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (6/6), 1.32 KiB | 1.32 MiB/s, done. From https://github.com/Metastem/wikiless cd561d0..23087c5 main -> origin/main Updating cd561d0..23087c5 Fast-forward README.md | 12 ------------ docker-compose.yml | 8 +++----- 2 files changed, 3 insertions(+), 17 deletions(-) [ nowhere.moe ] [ /dev/pts/0 ] [/srv/wikiless] → vim docker-compose.yml ; vim wikiless.config [ nowhere.moe ] [ /dev/pts/0 ] [/srv/wikiless] → cat wikiless.config const config = { /** * Set these configs below to suite your environment. */ domain: process.env.DOMAIN || 'wikiless.nowhere.moe', // Set to your own domain default_lang: process.env.DEFAULT_LANG || 'en', // Set your own language by default theme: process.env.THEME || 'dark', // Set to 'white' or 'dark' by default http_addr: process.env.HTTP_ADDR || '0.0.0.0', // don't touch, unless you know what your doing nonssl_port: process.env.NONSSL_PORT || 8080, // don't touch, unless you know what your doing /** * You can configure redis below if needed. * By default Wikiless uses 'redis://127.0.0.1:6379' as the Redis URL. * Versions before 0.1.1 Wikiless used redis_host and redis_port properties, * but they are not supported anymore. * process.env.REDIS_HOST is still here for backwards compatibility. */ redis_url: process.env.REDIS_URL || process.env.REDIS_HOST || 'redis://127.0.0.1:6379', redis_password: process.env.REDIS_PASSWORD, /** * You might need to change these configs below if you host through a reverse * proxy like nginx. */ trust_proxy: process.env.TRUST_PROXY === 'true' || true, trust_proxy_address: process.env.TRUST_PROXY_ADDRESS || '127.0.0.1', /** * Redis cache expiration values (in seconds). * When the cache expires, new content is fetched from Wikipedia (when the * given URL is revisited). */ setexs: { wikipage: process.env.WIKIPAGE_CACHE_EXPIRATION || (60 * 60 * 1), // 1 hour }, /** * Wikimedia requires a HTTP User-agent header for all Wikimedia related * requests. It's a good idea to change this to something unique. * Read more: https://meta.wikimedia.org/wiki/User-Agent_policy */ wikimedia_useragent: process.env.wikimedia_useragent || 'Wikiless media proxy bot (https://github.com/Metastem/wikiless)', /** * Cache control. Wikiless can automatically remove the cached media files from * the server. Cache control is on by default. * 'cache_control_interval' sets the interval for often the cache directory * is emptied (in hours). Default is every 24 hours. */ cache_control: process.env.CACHE_CONTROL !== 'true' || true, cache_control_interval: process.env.CACHE_CONTROL_INTERVAL || 24, } module.exports = config [ nowhere.moe ] [ /dev/pts/0 ] [/srv/wikiless] → cat docker-compose.yml version: "3.7" services: wikiless: build: context: . dockerfile: Dockerfile container_name: wikiless hostname: wikiless restart: always networks: wikiless_net: ipv4_address: 172.4.0.6 environment: REDIS_HOST: redis://172.4.0.5:6379 ports: - "127.0.0.1:8180:8080" # change port if needed security_opt: - no-new-privileges:true cap_drop: - ALL depends_on: - wikiless-redis wikiless-redis: container_name: wikiless-redis hostname: wikiless-redis image: redis:latest restart: always networks: wikiless_net: ipv4_address: 172.4.0.5 ports: - "6379" user: nobody read_only: true security_opt: - no-new-privileges:true tmpfs: - /data:size=10M,mode=0770,uid=65534,gid=65534,noexec,nosuid,nodev cap_drop: - ALL cap_add: - SETGID - SETUID - DAC_OVERRIDE networks: wikiless_net: ipam: config: - subnet: 172.4.0.0/16 [ nowhere.moe ] [ /dev/pts/0 ] [/srv/wikiless] → ls docker-compose.yml LICENSE.md media nginx.conf package.json package-lock.json README.md SECURITY.md src static wikiless.config [ nowhere.moe ] [ /dev/pts/0 ] [/srv/wikiless] → [ nowhere.moe ] [ /dev/pts/0 ] [/srv/wikiless] → vim Dockerfile [ nowhere.moe ] [ /dev/pts/0 ] [/srv/wikiless] → docker-compose down Stopping wikiless ... done Stopping wikiless-redis ... done Removing wikiless ... done Removing wikiless-redis ... done Removing network wikiless_wikiless_net [ nowhere.moe ] [ /dev/pts/0 ] [/srv/wikiless] → docker-compose up -d --build Creating network "wikiless_wikiless_net" with the default driver Building wikiless Step 1/9 : FROM node:20-alpine3.17 AS build 20-alpine3.17: Pulling from library/node 4db1b89c0bd1: Pull complete c14d172ed001: Pull complete c07dc96d4e30: Pull complete db1d0c17eb17: Pull complete Digest: sha256:e6df1a7e4da3c01fee080bfb504dc5b980a19bea23bd1884629469b55d6cd02f Status: Downloaded newer image for node:20-alpine3.17 ---> 063cc1778b5d Step 2/9 : WORKDIR /wikiless ---> Running in 85a222226267 Removing intermediate container 85a222226267 ---> ec73414a5f0a Step 3/9 : COPY . /wikiless ---> 97c84d369440 Step 4/9 : RUN npm install --no-optional ---> Running in 53377f121301 npm WARN config optional Use `--omit=optional` to exclude optional dependencies, or npm WARN config `--include=optional` to include them. npm WARN config npm WARN config Default value does install optional deps unless otherwise omitted. added 117 packages, and audited 118 packages in 2s 23 packages are looking for funding run `npm fund` for details found 0 vulnerabilities npm notice npm notice New minor version of npm available! 9.7.2 -> 9.8.0 npm notice Changelog: <****https://github.com/npm/cli/releases/tag/v9.8.0> npm notice Run `npm install -g npm@9.8.0` to update! npm notice Removing intermediate container 53377f121301 ---> a0ca7a91b7b4 Step 5/9 : FROM gcr.io/distroless/nodejs20-debian11 latest: Pulling from distroless/nodejs20-debian11 a7ca0d9ba68f: Already exists fe5ca62666f0: Already exists b02a7525f878: Already exists fcb6f6d2c998: Already exists e8c73c638ae9: Already exists 1e3d9b7d1452: Already exists 4aa0ea1413d3: Already exists 7c881f9ab25e: Already exists 5627a970d25e: Already exists 96266735468f: Already exists 2758d0c31c8c: Already exists 08553ba93cfe: Already exists dfc02eb7708f: Already exists 52907d314ddc: Already exists 4eec690774a4: Already exists 960f4c0076bf: Already exists Digest: sha256:9468dc4069714f71a30c6075027f75edca89cc4b30d1afc6741c3430def76d7f Status: Downloaded newer image for gcr.io/distroless/nodejs20-debian11:latest ---> b0a23627a0ab Step 6/9 : COPY --from=build /wikiless /wikiless ---> 72b7dee566ed Step 7/9 : WORKDIR /wikiless ---> Running in 3f227aaf0a85 Removing intermediate container 3f227aaf0a85 ---> 1cb668fc638e Step 8/9 : COPY wikiless.config config.js ---> cba58fa6593a Step 9/9 : CMD ["src/wikiless.js"] ---> Running in ac6bf21520f9 Removing intermediate container ac6bf21520f9 ---> 7c3ecb0313e1 Successfully built 7c3ecb0313e1 Successfully tagged wikiless_wikiless:latest Creating wikiless-redis ... done Creating wikiless ... done then install the reverse nginx proxyi, by default the app is available on local port 8180: [ nowhere.moe ] [ /dev/pts/2 ] [/srv/wikiless] → nmap 127.0.0.1 -p 8180 Starting Nmap 7.93 ( https://nmap.org ) at 2023-07-16 16:01 CEST Nmap scan report for localhost.localdomain (127.0.0.1) Host is up (0.00010s latency). PORT STATE SERVICE 8180/tcp open unknown Nmap done: 1 IP address (1 host up) scanned in 0.13 seconds root@Datura /srv/wikiless # cd /etc/nginx/sites-available/ root@Datura /etc/nginx/sites-available # vim wikiless.nowhere.moe.conf [ nowhere.moe ] [ /dev/pts/0 ] [/etc/nginx/sites-available] → cat /etc/nginx/sites-available/wikiless.nowhere.moe.conf server { server_name wikiless.nowhere.moe; listen 443 ssl; listen [::]:443 ssl; #http2 on; ssl_certificate /etc/acme/certs/wikiless.nowhere.moe/wikiless.nowhere.moe.cer; ssl_certificate_key /etc/acme/certs/wikiless.nowhere.moe/wikiless.nowhere.moe.key; #ssl_certificate /etc/letsencrypt/live/wikiless.nowhere.moe/fullchain.pem; #ssl_certificate_key /etc/letsencrypt/live/wikiless.nowhere.moe/privkey.pem; #include /etc/letsencrypt/options-ssl-nginx.conf; #ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; add_header strict_sni on; add_header strict_sni_header on; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header Content-Security-Policy upgrade-insecure-requests; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options "DENY"; add_header Clear-Site-Data "cookies"; add_header Referrer-Policy "no-referrer"; add_header Permissions-Policy "interest-cohort=(),accelerometer=(),ambient-light-sensor=(),autoplay=(),camera=(),encrypted-media=(),focus-without-user-activation=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),midi=(),payment=(),picture-in-picture=(),speaker=(),sync-xhr=(),usb=(),vr=()"; resolver 1.1.1.1; #ssl_trusted_certificate /etc/letsencrypt/live/wikiless.nowhere.moe/chain.pem; #ssl_trusted_certificate /etc/acme/certs/wikiless.nowhere.moe/wikiless.nowhere.moe.cer; #ssl_stapling on; #ssl_stapling_verify on; access_log /dev/null; error_log /dev/null; location / { proxy_set_header X-Forwarded-For $remote_addr; proxy_pass http://localhost:8180; } } server { listen 80; listen [::]:80; server_name wikiless.nowhere.moe; return 301 https://wikiless.nowhere.moe$request_uri; } root@Datura /etc/nginx/sites-available # ln -s /etc/nginx/sites-available/wikiless.nowhere.moe.conf /etc/nginx/sites-enabled/ root@Datura /etc/nginx/sites-available # systemctl stop nginx root@Datura /etc/nginx/sites-available # acme.sh --issue --standalone -d wikiless.nowhere.moe -k 4096 root@Datura /etc/nginx/sites-available # nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful root@Datura /etc/nginx/sites-available # systemctl restart nginx then check that your instance is working here: ![](1.png) Next we're going to make sure the website is accessible over tor: [ nowhere.moe ] [ /dev/pts/2 ] [/srv] → cat /etc/nginx/sites-available/wikiless.nowhere.moe.conf server { server_name wikiless.nowhere.moe; listen 443 ssl; listen [::]:443 ssl; #http2 on; ssl_certificate /etc/acme/certs/wikiless.nowhere.moe/wikiless.nowhere.moe.cer; ssl_certificate_key /etc/acme/certs/wikiless.nowhere.moe/wikiless.nowhere.moe.key; ######## TOR CHANGES ######## listen 4444 ssl; listen [::]:4444 ssl; server_name wikiless.daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion; add_header Onion-Location "http://wikiless.daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion$request_uri" always; ######## TOR CHANGES ####### #ssl_certificate /etc/letsencrypt/live/wikiless.nowhere.moe/fullchain.pem; #ssl_certificate_key /etc/letsencrypt/live/wikiless.nowhere.moe/privkey.pem; #include /etc/letsencrypt/options-ssl-nginx.conf; #ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; add_header strict_sni on; add_header strict_sni_header on; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header Content-Security-Policy upgrade-insecure-requests; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options "DENY"; add_header Clear-Site-Data "cookies"; add_header Referrer-Policy "no-referrer"; add_header Permissions-Policy "interest-cohort=(),accelerometer=(),ambient-light-sensor=(),autoplay=(),camera=(),encrypted-media=(),focus-without-user-activation=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),midi=(),payment=(),picture-in-picture=(),speaker=(),sync-xhr=(),usb=(),vr=()"; resolver 1.1.1.1; #ssl_trusted_certificate /etc/letsencrypt/live/wikiless.nowhere.moe/chain.pem; #ssl_trusted_certificate /etc/acme/certs/wikiless.nowhere.moe/wikiless.nowhere.moe.cer; #ssl_stapling on; #ssl_stapling_verify on; access_log /dev/null; error_log /dev/null; location / { proxy_set_header X-Forwarded-For $remote_addr; proxy_pass http://localhost:8180; } } server { listen 80; listen [::]:80; server_name wikiless.nowhere.moe; return 301 https://wikiless.nowhere.moe$request_uri; } [ nowhere.moe ] [ /dev/pts/2 ] [/srv] → cat /etc/tor/torrc | grep 444 HiddenServicePort 80 127.0.0.1:4443 HiddenServicePort 443 127.0.0.1:4444 ![](2.png) It may give an ssl error but at least it serves everything over https over tor. Let me know if you managed to make this work without the need of https. And lastly let's make it update automatically via a cronjob: [ nowhere.moe ] [ /dev/pts/2 ] [/srv] → crontab -e @daily docker-compose -f /srv/wikiless/docker-compose.yml stop ; git -C /srv/wikiless/ pull ; docker-compose -f /srv/wikiless/docker-compose.yml up -d --build [ nowhere.moe ] [ /dev/pts/2 ] [/srv] → cronitor select Use the arrow keys to navigate: ↓ ↑ → ← ? Select job to run: ✔ docker-compose -f /srv/wikiless/docker-compose.yml stop ; git -C /srv/wikiless/ pull ; docker-compose -f /srv/wikiless/docker-compose.yml up -d --build ----► Running command: docker-compose -f /srv/wikiless/docker-compose.yml stop ; git -C /srv/wikiless/ pull ; docker-compose -f /srv/wikiless/docker-compose.yml up -d --build Stopping wikiless ... done Stopping wikiless-redis ... done Already up to date. Building wikiless Step 1/9 : FROM node:20-alpine3.17 AS build ---> 063cc1778b5d Step 2/9 : WORKDIR /wikiless ---> Using cache ---> ec73414a5f0a Step 3/9 : COPY . /wikiless ---> Using cache ---> 97c84d369440 Step 4/9 : RUN npm install --no-optional ---> Using cache ---> a0ca7a91b7b4 Step 5/9 : FROM gcr.io/distroless/nodejs20-debian11 ---> b0a23627a0ab Step 6/9 : COPY --from=build /wikiless /wikiless ---> Using cache ---> 72b7dee566ed Step 7/9 : WORKDIR /wikiless ---> Using cache ---> 1cb668fc638e Step 8/9 : COPY wikiless.config config.js ---> Using cache ---> cba58fa6593a Step 9/9 : CMD ["src/wikiless.js"] ---> Using cache ---> 7c3ecb0313e1 Successfully built 7c3ecb0313e1 Successfully tagged wikiless_wikiless:latest Starting wikiless-redis ... done Recreating wikiless ... done ----► ✔ Command successful Elapsed time 13.038s