Switch from certbot to traefik

This commit is contained in:
Simon M. Haller-Seeber 2021-03-10 21:24:49 +01:00
parent 9344017322
commit ca58b4852a
8 changed files with 220 additions and 71 deletions

View File

@ -31,7 +31,7 @@ Sharelatex/Overleaf uses the email address to identify users: If you change the
in the mongo db.
```
docker exec -it mongo
docker exec -it mongo /bin/bash
mongo
use sharelatex
db.users.find({email:"EMAIL"}).pretty()
@ -56,7 +56,8 @@ MYDATA=/data
- sharelatex: all projects, tmp files, user files templates and ...
- letsencrypt: https certificates
*MYDOMAIN* is the FQDN for sharelatex and certbot (letsencrypt) <br/>
*MYDOMAIN* is the FQDN for sharelatex and traefik (letsencrypt) <br/>
*MYDOMAIN*:8443 Traefik Dashboard - Login uses traefik/user.htpasswd : user:admin pass:adminPass change this (e.g. generate a password with htpasswd)
*MYMAIL* is the admin mailaddress
```
@ -125,21 +126,15 @@ make
```
to generate the ldap-overleaf-sl docker image.
Then start docker containers:
Then start docker containers (with loadbalancer):
```
docker-compose up -d
export NUMINSTANCES=1
docker-compose up -d --scale sharelaatex=NUMINSTANCES
```
*Known Issue:*
During the first startup the certbot image will get an initial certificate - if that
happens not in a very timely manner sharelatex will fail to start (due to the missing certificates
nginx crashes). Solution: wait 10 seconds and restart the sharelatex container.
- Works up to sharelatex 2.3.1. After that at least issue #5 is introduced.
```
docker stop ldap-overleaf-sl
docker-compose up -d
```
After the inital startup and certificate configuration you can reconfigure the
docker-compose.yml that port 80 points to the Sharelatex/Overleaf instance.

View File

@ -1,27 +1,108 @@
version: '2.2'
services:
traefik:
image: traefik:latest
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- web
ports:
- 80:80
- 443:443
- 8443:8443
# - 8080:8080
# - 27017:27017
volumes:
- ${MYDATA}/letsencrypt:/letsencrypt
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik/dynamic_conf.yml:/dynamic_conf.yml
- ./traefik/users.htpasswd:/users.htpasswd
command:
- "--api=true"
- "--api.dashboard=true"
#- "--api.insecure=true" # provides the dashboard on http://IPADRESS:8080
- "--providers.docker=true"
- "--ping"
- "--providers.docker.network=web"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.web-secure.address=:443"
- "--entrypoints.web-admin.address=:8443"
- "--certificatesresolvers.myhttpchallenge.acme.httpchallenge=true"
- "--certificatesresolvers.myhttpchallenge.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.myhttpchallenge.acme.email=${MYMAIL}"
- "--certificatesresolvers.myhttpchallenge.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.mongo.address=:27017"
#- --certificatesresolvers.myhttpchallenge.acme.caserver=https://acme-v02.api.letsencrypt.org/directory
labels:
- "traefik.enable=true"
# To Fix enable dashboard on port 8443
- "traefik.http.routers.dashboard.entrypoints=web-admin"
- "traefik.http.routers.dashboard.rule=Host(`${MYDOMAIN}`)"
# - "traefik.http.routers.dashboard.rule=Host(`traefik.${MYDOMAIN}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
- "traefik.http.routers.dashboard.tls=true"
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.usersfile=/users.htpasswd"
- "traefik.http.routers.dashboard.service=api@internal"
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "1"
sharelatex:
restart: always
image: ldap-overleaf-sl:latest
container_name: ldap-overleaf-sl
depends_on:
mongo:
condition: service_healthy
redis:
condition: service_healthy
simple-certbot:
traefik:
condition: service_started
#simple-certbot:
# condition: service_started
privileged: false
ports:
- 443:443
networks:
- web
expose:
- 80
- 443
links:
- mongo
- redis
- simple-certbot
#- simple-certbot
volumes:
- ${MYDATA}/sharelatex:/var/lib/sharelatex
- ${MYDATA}/letsencrypt:/etc/letsencrypt
- ${MYDATA}/letsencrypt/live/${MYDOMAIN}/:/etc/letsencrypt/certs/domain
- ${MYDATA}/letsencrypt:/etc/letsencrypt:ro
# - ${MYDATA}/letsencrypt/live/${MYDOMAIN}/:/etc/letsencrypt/certs/domain
labels:
- "traefik.enable=true"
- "traefik.http.routers.tex.entrypoints=web"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.sharel.middlewares=redirect-to-https@docker"
- "traefik.http.routers.sharel-secured.rule=Host(`${MYDOMAIN}`)"
- "traefik.http.routers.sharel-secured.tls=true"
- "traefik.http.routers.sharel-secured.tls.certresolver=myhttpchallenge"
- "traefik.http.routers.sharel-secured.entrypoints=web-secure"
- "traefik.http.routers.proxy-https.entrypoints=web-secure"
- "traefik.http.routers.proxy-https.rule=Host(`${MYDOMAIN}`)"
- "traefik.http.services.sharel.loadbalancer.server.port=80"
- "traefik.http.services.sharel.loadbalancer.server.scheme=http"
# ToDo - internally connect via https: reuse the certifiacte from traefik (acme.json)
#- "traefik.http.services.sharel.loadbalancer.server.port=443"
#- "traefik.http.services.sharel.loadbalancer.server.scheme=https"
- "traefik.http.services.sharel.loadbalancer.sticky.cookie=true"
- "traefik.http.services.sharel.loadbalancer.sticky.cookie.name=io"
- "traefik.http.services.sharel.loadbalancer.sticky.cookie.httponly=true"
- "traefik.http.services.sharel.loadbalancer.sticky.cookie.secure=true"
- "traefik.http.services.sharel.loadbalancer.sticky.cookie.samesite=io"
environment:
SHARELATEX_APP_NAME: Overleaf
SHARELATEX_MONGO_URL: mongodb://mongo/sharelatex
@ -32,8 +113,6 @@ services:
SHARELATEX_LEFT_FOOTER: '[{"text": "Powered by <a href=\"https://www.sharelatex.com\">ShareLaTeX</a> 2016"} ]'
SHARELATEX_RIGHT_FOOTER: '[{"text": "LDAP Overleaf (beta)"} ]'
SHARELATEX_EMAIL_FROM_ADDRESS: "noreply@${MYDOMAIN}"
# SHARELATEX_EMAIL_AWS_SES_ACCESS_KEY_ID:
# SHARELATEX_EMAIL_AWS_SES_SECRET_KEY:
SHARELATEX_EMAIL_SMTP_HOST: smtp.${MYDOMAIN}
SHARELATEX_EMAIL_SMTP_PORT: 587
SHARELATEX_EMAIL_SMTP_SECURE: 'false'
@ -43,18 +122,31 @@ services:
# SHARELATEX_EMAIL_SMTP_IGNORE_TLS: false
SHARELATEX_CUSTOM_EMAIL_FOOTER: "This system is run by ${MYDOMAIN} - please contact ${MYMAIL} if you experience any issues."
# make public links accessible w/o login (link sharing issue)
# https://github.com/overleaf/docker-image/issues/66
# https://github.com/overleaf/overleaf/issues/628
# https://github.com/overleaf/web/issues/367
# Fixed in 2.0.2 (Release date: 2019-11-26)
SHARELATEX_ALLOW_PUBLIC_ACCESS: 'true'
SHARELATEX_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING: 'true'
SHARELATEX_SECURE_COOKIE: 'true'
SHARELATEX_BEHIND_PROXY: 'true'
LDAP_SERVER: ldaps://LDAPSERVER:636
LDAP_BASE: ou=people,dc=DOMAIN,dc=TLD
LDAP_BINDDN: ou=someunit,ou=people,dc=DOMAIN,dc=TLS
# By default tries to bind directly with the ldap user - this user has to be in the LDAP GROUP
# LDAP_GROUP_FILTER: '(memberof=cn=GROUPNAME,ou=groups,dc=DOMAIN,dc=TLD)'
LDAP_GROUP_FILTER: '(memberof=cn=GROUPNAME,ou=groups,dc=DOMAIN,dc=TLD)'
# If user is in ADMIN_GROUP on user creation (first login) isAdmin is set to true.
# Admin Users can invite external (non ldap) users. This feature makes only sense
# when ALLOW_EMAIL_LOGIN is set to 'true'. Additionally admins can send
# system wide messages.
#LDAP_ADMIN_GROUP_FILTER: '(memberof=cn=ADMINGROUPNAME,ou=groups,dc=DOMAIN,dc=TLD)'
ALLOW_EMAIL_LOGIN: 'false'
LDAP_ADMIN_GROUP_FILTER: '(memberof=cn=ADMINGROUPNAME,ou=groups,dc=DOMAIN,dc=TLD)'
ALLOW_EMAIL_LOGIN: 'true'
# All users in the LDAP_GROUP_FILTER are loaded from the ldap server into contacts.
# This LDAP search happens without bind. If you want this and your LDAP needs a bind you can
@ -76,7 +168,7 @@ services:
restart: always
image: mongo
container_name: mongo
ports:
expose:
- 27017
volumes:
- ${MYDATA}/mongo_data:/data/db
@ -85,6 +177,14 @@ services:
interval: 10s
timeout: 10s
retries: 5
labels:
- "traefik.enable=true"
- "traefik.tcp.routers.mongodb.rule=HostSNI(`*`)"
- "traefik.tcp.services.mongodb.loadbalancer.server.port=27017"
- "traefik.tcp.routers.mongodb.tls=true"
- "traefik.tcp.routers.mongodb.entrypoints=mongo"
networks:
- web
redis:
restart: always
@ -98,7 +198,7 @@ services:
sysctls:
- net.core.somaxconn=65535
# - vm.overcommit_memory=1
ports:
expose:
- 6379
volumes:
- ${MYDATA}/redis_data:/data
@ -107,23 +207,30 @@ services:
interval: 10s
timeout: 5s
retries: 5
networks:
- web
simple-certbot:
restart: always
image: certbot/certbot
container_name: simple-certbot
ports:
- 80:80
volumes:
- ${MYDATA}/letsencrypt:/etc/letsencrypt
# a bit hacky but this docker image uses very little disk-space
# best practices for ssl and nginx are set in the ldap-overleaf-sl Dockerfile
entrypoint:
- "/bin/sh"
- -c
- |
trap exit TERM;\
certbot certonly --standalone -d ${MYDOMAIN} --agree-tos -m ${MYMAIL} -n ; \
while :; do certbot renew; sleep 240h & wait $${!}; done;
# simple-certbot:
# restart: always
# image: certbot/certbot
# container_name: simple-certbot
# ports:
# - 80:80
# volumes:
# - ${MYDATA}/letsencrypt:/etc/letsencrypt
# # a bit hacky but this docker image uses very little disk-space
# # best practices for ssl and nginx are set in the ldap-overleaf-sl Dockerfile
# entrypoint:
# - "/bin/sh"
# - -c
# - |
# trap exit TERM;\
# certbot certonly --standalone -d ${MYDOMAIN} --agree-tos -m ${MYMAIL} -n ; \
# while :; do certbot renew; sleep 240h & wait $${!}; done;
#
networks:
web:
external: true

View File

@ -1,4 +1,4 @@
FROM sharelatex/sharelatex:latest
FROM sharelatex/sharelatex:2.3.1
LABEL maintainer="Simon Haller-Seeber"
LABEL version="0.1"
@ -7,14 +7,15 @@ ARG collab_text
ARG login_text
# set workdir (might solve issue #2 - see https://stackoverflow.com/questions/57534295/)
WORKDIR /var/www/sharelatex
WORKDIR /var/www/sharelatex/web
# install latest npm
RUN npm install -g npm
# clean cache (might solve issue #2)
RUN npm cache clean --force
#RUN npm cache clean --force
RUN npm install ldapts-search
RUN npm install ldapts
#RUN npm install bcrypt@5.0.0
# This variant of updateing texlive does not work
#RUN bash -c tlmgr install scheme-full
@ -48,7 +49,7 @@ COPY sharelatex/admin-index.pug /var/www/sharelatex/web/app/views/admin/index.p
RUN rm /var/www/sharelatex/web/app/views/admin/register.pug
### To remove comments entirly (bug https://github.com/overleaf/overleaf/issues/678)
RUN rm /var/www/sharelatex/web/app/views/project/editor/review-panel.pug
#RUN rm /var/www/sharelatex/web/app/views/project/editor/review-panel.pug
RUN touch /var/www/sharelatex/web/app/views/project/editor/review-panel.pug
### Nginx and Certificates
@ -63,3 +64,10 @@ RUN wget https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbo
# reload nginx via cron for reneweing https certificates automatically
COPY nginx/nginx-reload.sh /etc/cron.weekly/
RUN chmod 0744 /etc/cron.weekly/nginx-reload.sh
## extract certificates from acme.json?
# COPY nginx/nginx-cert.sh /etc/cron.weekly/
# RUN chmod 0744 /etc/cron.weekly/nginx-cert.sh
# RUN echo "/usr/cron.weekly/nginx-cert.sh 2>&1 > /dev/null" > /etc/rc.local
# RUN chmod 0744 /etc/rc.local

View File

@ -0,0 +1,3 @@
#!/bin/bash
less /etc/letsencrypt/acme.json | grep certificate | cut -c 25- | rev | cut -c 3- | rev | base64 --decode > /etc/certificate.crt
less /etc/letsencrypt/acme.json | grep key | cut -c 17- | rev | cut -c 3- | rev | base64 --decode > /etc/key.crt

View File

@ -1,31 +1,31 @@
server {
listen 80;
server_name _; # Catch all, see http://nginx.org/en/docs/http/server_names.html
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
# location / {
# return 301 https://$host$request_uri;
# }
#}
#
#
#server {
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
# server_name _; # Catch all
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _; # Catch all
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
server_tokens off;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
set $static_path /var/www/sharelatex/web/public;
ssl_certificate /etc/letsencrypt/certs/domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/certs/domain/privkey.pem;
include /etc/nginx/options-ssl-nginx.conf;
ssl_dhparam /etc/nginx/ssl-dhparams.pem;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# ssl_certificate /etc/certificate.crt;
# ssl_certificate_key /etc/key.crt;
# ssl_certificate /etc/letsencrypt/certs/domain/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/certs/domain/privkey.pem;
# include /etc/nginx/options-ssl-nginx.conf;
# ssl_dhparam /etc/nginx/ssl-dhparams.pem;
#
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;

View File

@ -57,6 +57,8 @@ const AuthenticationManager = {
//console.log("Creating User:" + JSON.stringify(query))
//create random pass for local userdb, does not get checked for ldap users during login
let pass = require("crypto").randomBytes(32).toString("hex")
console.log("Creating User:" + JSON.stringify(query) + "Random Pass" + pass)
const userRegHand = require('../User/UserRegistrationHandler.js')
userRegHand.registerNewUser({
email: mail,
@ -179,7 +181,7 @@ const AuthenticationManager = {
checkRounds(user, hashedPassword, password, callback) {
// Temporarily disable this function, TODO: re-enable this
//callback()
return callback()
if (Settings.security.disableBcryptRoundsUpgrades) {
return callback()
}
@ -212,7 +214,7 @@ const AuthenticationManager = {
}
db.users.update(
{
_id: ObjectId(userId._id.toString())
_id: ObjectId(userId.toString())
},
{
$set: {

33
traefik/dynamic_conf.yml Normal file
View File

@ -0,0 +1,33 @@
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true
http:
middlewares:
secHeaders:
headers:
browserXssFilter: true
contentTypeNosniff: true
frameDeny: true
sslRedirect: true
#HSTS Configuration
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: "SAMEORIGIN"
https-redirect:
redirectScheme:
scheme: https

1
traefik/users.htpasswd Normal file
View File

@ -0,0 +1 @@
admin:$apr1$7xGHLKlO$Mx2DNcWfqiHfH1WLg51ul.