In this tutorial we're going to check out how to install Wikiless, a privacy front-end for wikipedia.
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:
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
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
Donate XMR: 8AUYjhQeG3D5aodJDtqG499N5jXXM71gYKD8LgSsFB9BUV1o7muLv3DXHoydRTK4SZaaUBq4EAUqpZHLrX2VZLH71Jrd9k8
Contact: nihilist@contact.nowhere.moe (PGP)