Discourse’s official installation guide claims that you can setup Discourse with zero knowledge of Rails or Linux shell thanks to Docker. However, it is only true when you deploy it outside China, due to inevitably unstable network conditions.
tl;dr
Use tun2socks to route all your traffic to international Internet and ./launcher rebuild app --docker-args --net=host --skip-mac-address
to build Discourse.
What if you follow official guide
host git
fails
The launcher
script hangs for quite a while and then fails. It can be fixed by adding to ~/.gitconfig
:
[http]
postBuffer = 157286400
proxy = socks5://127.0.0.1:1080
container git
fails
launcher
script creates multiple Docker containers, inside which Discourse’s source code is obtained via git
. I met two kinds of error:
- Cannot resolve ‘github.com’
- TLS connection to ‘github.com’ fails
Solution:
add sudo -H -E -u discourse git config --global http.proxy socks5://127.0.0.1:3999
to templates/web.template.yml
container yarn
and npm
fails
Either hangs or too slow until abort lastly.
Solution:
Use privoxy
to convert socks5 proxy to http proxy and then add to templates/web.template.yml
the following:
su discourse -c 'npm config set proxy http://127.0.0.1:2080'
su discourse -c 'npm config set https-proxy http://127.0.0.1:2080'
su discourse -c 'yarn config set proxy http://127.0.0.1:2080'
su discourse -c 'yarn config set https-proxy http://127.0.0.1:2080'
I also tried to add environment variables to templates/web.template.yml
and containers/app.yml
:
HTTP_PROXY: http://127.0.0.1:4099
HTTPS_PROXY: http://127.0.0.1:4099
But it fails halfway.
even if you have done this much, it still fails
abort when executing: su discourse -c 'bundle exec rake themes:update assets:precompile'
Ultimate solution
global proxy
This configuration above is extremely tiresome: every time you modify one place, you run launcher
, wait several minutes only to end up with failure. The most annoying part is that after so many failed tries it still won’t work.
The ultimate solution is to use tun2socks, which will route all your traffic to international Internet.
I also tried using iptables / nftables, ss-tproxy, and Configure Docker to use a proxy server | Docker Documentation , however Docker container’s traffic still won’t go through proxy.
Here are the steps:
# add tun device and setup route table
ip tuntap add mode tun dev tun0
ip addr add 198.18.0.1/15 dev tun0
ip link set dev tun0 up
ip route del default
ip route add default via 198.18.0.1 dev tun0 metric 1
ip r
# start socks5 to tun converter
tun2socks --device tun0 --proxy socks5://127.0.0.1:5608 -interface enp12s0
# configure sysctl
sysctl net.ipv4.conf.all.rp_filter=0
sysctl net.ipv4.conf.enp12s0.rp_filter=0
# redirect DNS traffic
iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to 8.8.8.8:53;
iptables -t nat -A POSTROUTING -p udp -d 8.8.8.8 --dport 53 -o eth3 -j MASQUERADE;
# check what is your public IP address now
curl https://ip.lqy.me
./launcher rebuild app
Use --net=host
option to make the programs inside the Docker container look as if they are running on the host. Also pass --skip-mac-address
option to launcher
script otherwise it will also fail.
The full command to build Discourse is:
cd /var/discourse
clone https://github.com/discourse/discourse_docker.git discourse
# modify containers/app.yml or run `./discourse-setup`
./launcher rebuild app --docker-args --net=host --skip-mac-address
# if succeed, Discourse will start and listening to 80 / 443 / var/discourse/shared/standalone/nginx.http.sock
# it will auto-start on-boot as long as your docker.service is enabled
You may need a caddy
/ nginx
to do reverse proxy to Discourse’s unix socket.
Here is /etc/caddy/Caddyfile
:
lqy.me:443 {
tls /etc/caddy/ssl/cer /etc/caddy/ssl/key
# requires `- "templates/web.socketed.template.yml"` to be included in `containers/app.yml`
reverse_proxy * unix//var/discourse/shared/standalone/nginx.http.sock
log {
output file /var/log/caddy/lqy.me.log
}
}
and /etc/nginx/nginx.conf
:
server {
listen 0.0.0.0:443 ssl;
server_name lqy.me;
access_log /var/log/nginx/access.lqy.me.log compression;
error_log /var/log/nginx/error.lqy.me.log;
ssl_certificate /etc/caddy/ssl/cer;
ssl_certificate_key /etc/caddy/ssl/key;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_dhparam /etc/nginx/dhparam;
ssl_protocols TLSv1.3;
ssl_ciphers ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_stapling_verify on;
# replace with the IP address of your resolver
#resolver 127.0.0.1;
# optionally add a HSTS header:
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
ssl_session_cache shared:MozSSL443:10m;
location / {
proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
}