├── .dockerignore ├── .editorconfig ├── .gitignore ├── Dockerfile ├── Dockerfile-base ├── Makefile ├── README.md ├── git-revision.sh ├── hotfix ├── 2.0.1 │ ├── Dockerfile │ ├── create_and_destroy_users.patch │ └── disable_project_history.patch ├── 2.0.2 │ ├── 1-anon-upload.patch │ ├── 2-read-only-access.patch │ ├── 3-url-linking-1.patch │ ├── 4-url-linking-2.patch │ ├── 5-disable-analytics-1.patch │ ├── 6-disable-analytics-2.patch │ └── Dockerfile └── 2.1.1 │ ├── Dockerfile │ └── add-recaptcha-config.patch ├── init_scripts ├── 00_make_sharelatex_data_dirs.sh ├── 00_regen_sharelatex_secrets.sh ├── 00_set_docker_host_ipaddress.sh ├── 98_check_db_access.sh └── 99_migrate.sh ├── logrotate └── sharelatex ├── nginx ├── nginx.conf └── sharelatex.conf ├── runit ├── chat-sharelatex │ └── run ├── clsi-sharelatex │ └── run ├── contacts-sharelatex │ └── run ├── docstore-sharelatex │ └── run ├── document-updater-sharelatex │ └── run ├── filestore-sharelatex │ └── run ├── nginx │ └── run ├── notifications-sharelatex │ └── run ├── real-time-sharelatex │ └── run ├── spelling-sharelatex │ └── run ├── tags-sharelatex │ └── run ├── track-changes-sharelatex │ └── run └── web-sharelatex │ └── run ├── services.js └── settings.coffee /.dockerignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .git/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | api-data 4 | versions/ 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # --------------------------------------------- 2 | # Overleaf Community Edition (overleaf/overleaf) 3 | # --------------------------------------------- 4 | 5 | FROM sharelatex/sharelatex-base:latest 6 | 7 | ENV SHARELATEX_CONFIG /etc/sharelatex/settings.coffee 8 | 9 | 10 | # Checkout Overleaf Community Edition repo 11 | # ---------------------------------------- 12 | RUN git clone https://github.com/overleaf/overleaf.git \ 13 | --depth 1 /var/www/sharelatex 14 | 15 | 16 | # Copy build dependencies 17 | # ----------------------- 18 | ADD ${baseDir}/git-revision.sh /var/www/git-revision.sh 19 | ADD ${baseDir}/services.js /var/www/sharelatex/config/services.js 20 | 21 | 22 | # Checkout services 23 | # ----------------- 24 | RUN cd /var/www/sharelatex \ 25 | && npm install \ 26 | && grunt install \ 27 | \ 28 | # Cleanup not needed artifacts 29 | # ---------------------------- 30 | && rm -rf /root/.cache /root/.npm $(find /tmp/ -mindepth 1 -maxdepth 1) \ 31 | # Stores the version installed for each service 32 | # --------------------------------------------- 33 | && cd /var/www \ 34 | && ./git-revision.sh > revisions.txt \ 35 | \ 36 | # Cleanup the git history 37 | # ------------------- 38 | && rm -rf $(find /var/www/sharelatex -name .git) 39 | 40 | # Install npm dependencies 41 | # ------------------------ 42 | RUN cd /var/www/sharelatex \ 43 | && bash ./bin/install-services \ 44 | \ 45 | # Cleanup not needed artifacts 46 | # ---------------------------- 47 | && rm -rf /root/.cache /root/.npm $(find /tmp/ -mindepth 1 -maxdepth 1) 48 | 49 | # Compile CoffeeScript 50 | # -------------------- 51 | RUN cd /var/www/sharelatex \ 52 | && bash ./bin/compile-services 53 | 54 | # Links CLSI sycntex to its default location 55 | # ------------------------------------------ 56 | RUN ln -s /var/www/sharelatex/clsi/bin/synctex /opt/synctex 57 | 58 | 59 | # Copy runit service startup scripts to its location 60 | # -------------------------------------------------- 61 | ADD ${baseDir}/runit /etc/service 62 | 63 | 64 | # Configure nginx 65 | # --------------- 66 | ADD ${baseDir}/nginx/nginx.conf /etc/nginx/nginx.conf 67 | ADD ${baseDir}/nginx/sharelatex.conf /etc/nginx/sites-enabled/sharelatex.conf 68 | 69 | 70 | # Configure log rotation 71 | # ---------------------- 72 | ADD ${baseDir}/logrotate/sharelatex /etc/logrotate.d/sharelatex 73 | 74 | 75 | # Copy Phusion Image startup scripts to its location 76 | # -------------------------------------------------- 77 | COPY ${baseDir}/init_scripts/ /etc/my_init.d/ 78 | 79 | # Copy app settings files 80 | # ----------------------- 81 | COPY ${baseDir}/settings.coffee /etc/sharelatex/settings.coffee 82 | 83 | # Set Environment Variables 84 | # -------------------------------- 85 | ENV WEB_API_USER "sharelatex" 86 | 87 | ENV SHARELATEX_APP_NAME "Overleaf Community Edition" 88 | 89 | 90 | EXPOSE 80 91 | 92 | WORKDIR / 93 | 94 | ENTRYPOINT ["/sbin/my_init"] 95 | 96 | -------------------------------------------------------------------------------- /Dockerfile-base: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------- 2 | # Overleaf Base Image (sharelatex/sharelatex-base) 3 | # -------------------------------------------------- 4 | 5 | FROM phusion/baseimage:0.11 6 | 7 | ENV baseDir . 8 | 9 | 10 | # Install dependencies 11 | # -------------------- 12 | RUN apt-get update \ 13 | && apt-get install -y \ 14 | build-essential wget net-tools unzip time imagemagick optipng strace nginx git python zlib1g-dev libpcre3-dev \ 15 | qpdf \ 16 | aspell aspell-en aspell-af aspell-am aspell-ar aspell-ar-large aspell-bg aspell-bn aspell-br aspell-ca aspell-cs aspell-cy aspell-da aspell-de aspell-el aspell-eo aspell-es aspell-et aspell-eu-es aspell-fa aspell-fo aspell-fr aspell-ga aspell-gl-minimos aspell-gu aspell-he aspell-hi aspell-hr aspell-hsb aspell-hu aspell-hy aspell-id aspell-is aspell-it aspell-kk aspell-kn aspell-ku aspell-lt aspell-lv aspell-ml aspell-mr aspell-nl aspell-nr aspell-ns aspell-pa aspell-pl aspell-pt aspell-pt-br aspell-ro aspell-ru aspell-sk aspell-sl aspell-ss aspell-st aspell-sv aspell-tl aspell-tn aspell-ts aspell-uk aspell-uz aspell-xh aspell-zu \ 17 | \ 18 | # install Node.JS 10 19 | && curl -sSL https://deb.nodesource.com/setup_10.x | bash - \ 20 | && apt-get install -y nodejs \ 21 | \ 22 | && rm -rf \ 23 | # We are adding a custom nginx config in the main Dockerfile. 24 | /etc/nginx/nginx.conf \ 25 | /etc/nginx/sites-enabled/default \ 26 | /var/lib/apt/lists/* 27 | 28 | # Install Grunt 29 | # ------------ 30 | RUN npm install -g \ 31 | grunt-cli \ 32 | && rm -rf /root/.npm 33 | 34 | # Install TexLive 35 | # --------------- 36 | # CTAN mirrors occasionally fail, in that case install TexLive against an 37 | # specific server, for example http://ctan.crest.fr 38 | # 39 | # # docker build \ 40 | # --build-arg TEXLIVE_MIRROR=http://ctan.crest.fr/tex-archive/systems/texlive/tlnet \ 41 | # -f Dockerfile-base -t sharelatex/sharelatex-base . 42 | ARG TEXLIVE_MIRROR=http://mirror.ctan.org/systems/texlive/tlnet 43 | 44 | ENV PATH "${PATH}:/usr/local/texlive/2019/bin/x86_64-linux" 45 | 46 | RUN mkdir /install-tl-unx \ 47 | && curl -sSL \ 48 | ${TEXLIVE_MIRROR}/install-tl-unx.tar.gz \ 49 | | tar -xzC /install-tl-unx --strip-components=1 \ 50 | \ 51 | && echo "tlpdbopt_autobackup 0" >> /install-tl-unx/texlive.profile \ 52 | && echo "tlpdbopt_install_docfiles 0" >> /install-tl-unx/texlive.profile \ 53 | && echo "tlpdbopt_install_srcfiles 0" >> /install-tl-unx/texlive.profile \ 54 | && echo "selected_scheme scheme-basic" >> /install-tl-unx/texlive.profile \ 55 | \ 56 | && /install-tl-unx/install-tl \ 57 | -profile /install-tl-unx/texlive.profile \ 58 | -repository ${TEXLIVE_MIRROR} \ 59 | \ 60 | && tlmgr install --repository ${TEXLIVE_MIRROR} \ 61 | latexmk \ 62 | texcount \ 63 | \ 64 | && rm -rf /install-tl-unx 65 | 66 | 67 | # Set up sharelatex user and home directory 68 | # ----------------------------------------- 69 | RUN adduser --system --group --home /var/www/sharelatex --no-create-home sharelatex && \ 70 | mkdir -p /var/lib/sharelatex && \ 71 | chown www-data:www-data /var/lib/sharelatex && \ 72 | mkdir -p /var/log/sharelatex && \ 73 | chown www-data:www-data /var/log/sharelatex && \ 74 | mkdir -p /var/lib/sharelatex/data/template_files && \ 75 | chown www-data:www-data /var/lib/sharelatex/data/template_files 76 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | 3 | 4 | build-base: 5 | docker build -f Dockerfile-base -t sharelatex/sharelatex-base . 6 | 7 | 8 | build-community: 9 | docker build -f Dockerfile -t sharelatex/sharelatex . 10 | 11 | 12 | PHONY: build-base build-community 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overleaf Docker Image 2 | 3 | **THIS REPOSITORY HAS BEEN MERGED INTO https://github.com/overleaf/overleaf .** 4 | 5 | This is the source for building the Overleaf community-edition docker image. 6 | 7 | 8 | ## End-User Install 9 | Please see the [offical wiki for install 10 | guides](https://github.com/overleaf/overleaf/wiki) 11 | 12 | 13 | ## Development 14 | 15 | This repo contains two dockerfiles, `Dockerfile-base`, which builds the 16 | `sharelatex/sharelatex-base` image, and `Dockerfile` which builds the 17 | `sharelatex/sharelatex` (or "community") image. 18 | 19 | The Base image generally contains the basic dependencies like `wget` and 20 | `aspell`, plus `texlive`. We split this out because it's a pretty heavy set of 21 | dependencies, and it's nice to not have to rebuild all of that every time. 22 | 23 | The `sharelatex/sharelatex` image extends the base image and adds the actual Overleaf code 24 | and services. 25 | 26 | Use `make build-base` and `make build-community` to build these images. 27 | 28 | 29 | ### How the Overleaf code gets here 30 | 31 | This repo uses [the public Overleaf 32 | repository](https://github.com/overleaf/overleaf), which used to be the main 33 | public source for the Overleaf system. 34 | 35 | That repo is cloned down into the docker image, and a script then installs all 36 | the services. 37 | 38 | 39 | ### How services run inside the container 40 | 41 | We use the [Phusion base-image](https://github.com/phusion/baseimage-docker) 42 | (which is extended by our `base` image) to provide us with a VM-like container 43 | in which to run the Overleaf services. Baseimage uses the `runit` service 44 | manager to manage services, and we add our init-scripts from the `./runit` 45 | folder. 46 | -------------------------------------------------------------------------------- /git-revision.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | for gitDir in $(find "$PWD" -name .git); do 4 | echo -n "$(dirname ${gitDir})," 5 | git --git-dir="$gitDir" rev-parse HEAD 6 | done 7 | -------------------------------------------------------------------------------- /hotfix/2.0.1/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM sharelatex/sharelatex:2.0.0 2 | 3 | 4 | # Patch 1: Fixes project deletion (https://github.com/overleaf/overleaf/issues/644) 5 | ADD disable_project_history.patch /etc/sharelatex/disable_project_history.patch 6 | RUN cd /etc/sharelatex && \ 7 | patch < disable_project_history.patch 8 | 9 | 10 | # Patch 2: Fixes admin creation via CLI (https://github.com/overleaf/overleaf/issues/647) 11 | ADD create_and_destroy_users.patch /var/www/sharelatex/tasks/create_and_destroy_users.patch 12 | RUN cd /var/www/sharelatex/tasks/ && \ 13 | patch < create_and_destroy_users.patch 14 | -------------------------------------------------------------------------------- /hotfix/2.0.1/create_and_destroy_users.patch: -------------------------------------------------------------------------------- 1 | --- CreateAndDestoryUsers.coffee 2 | +++ CreateAndDestoryUsers.coffee 3 | @@ -21,7 +21,7 @@ module.exports = (grunt) -> 4 | user.save (error) -> 5 | throw error if error? 6 | ONE_WEEK = 7 * 24 * 60 * 60 # seconds 7 | - OneTimeTokenHandler.getNewToken user._id, { expiresIn: ONE_WEEK }, (err, token)-> 8 | + OneTimeTokenHandler.getNewToken "password", { expiresIn: ONE_WEEK, email:user.email, user_id: user._id.toString() }, (err, token)-> 9 | return next(err) if err? 10 | 11 | console.log "" 12 | -------------------------------------------------------------------------------- /hotfix/2.0.1/disable_project_history.patch: -------------------------------------------------------------------------------- 1 | --- settings.coffee 2 | +++ settings.coffee 3 | @@ -200,6 +200,8 @@ settings = 4 | # is not available 5 | v1: 6 | url: "" 7 | + project_history: 8 | + enabled: false 9 | references:{} 10 | notifications:undefined 11 | 12 | -------------------------------------------------------------------------------- /hotfix/2.0.2/1-anon-upload.patch: -------------------------------------------------------------------------------- 1 | --- UploadsRouter.js 2 | +++ UploadsRouter.js 3 | @@ -1,13 +1,3 @@ 4 | -/* eslint-disable 5 | - no-unused-vars, 6 | -*/ 7 | -// TODO: This file was created by bulk-decaffeinate. 8 | -// Fix any style issues and re-enable lint. 9 | -/* 10 | - * decaffeinate suggestions: 11 | - * DS102: Remove unnecessary code created because of implicit returns 12 | - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md 13 | - */ 14 | const AuthorizationMiddleware = require('../Authorization/AuthorizationMiddleware') 15 | const AuthenticationController = require('../Authentication/AuthenticationController') 16 | const ProjectUploadController = require('./ProjectUploadController') 17 | @@ -28,18 +18,30 @@ module.exports = { 18 | ProjectUploadController.uploadProject 19 | ) 20 | 21 | - return webRouter.post( 22 | - '/Project/:Project_id/upload', 23 | - RateLimiterMiddleware.rateLimit({ 24 | - endpointName: 'file-upload', 25 | - params: ['Project_id'], 26 | - maxRequests: 200, 27 | - timeInterval: 60 * 30 28 | - }), 29 | - AuthenticationController.requireLogin(), 30 | - AuthorizationMiddleware.ensureUserCanWriteProjectContent, 31 | - ProjectUploadController.multerMiddleware, 32 | - ProjectUploadController.uploadFile 33 | - ) 34 | + const fileUploadEndpoint = '/Project/:Project_id/upload' 35 | + const fileUploadRateLimit = RateLimiterMiddleware.rateLimit({ 36 | + endpointName: 'file-upload', 37 | + params: ['Project_id'], 38 | + maxRequests: 200, 39 | + timeInterval: 60 * 30 40 | + }) 41 | + if (Settings.allowAnonymousReadAndWriteSharing) { 42 | + webRouter.post( 43 | + fileUploadEndpoint, 44 | + fileUploadRateLimit, 45 | + AuthorizationMiddleware.ensureUserCanWriteProjectContent, 46 | + ProjectUploadController.multerMiddleware, 47 | + ProjectUploadController.uploadFile 48 | + ) 49 | + } else { 50 | + webRouter.post( 51 | + fileUploadEndpoint, 52 | + fileUploadRateLimit, 53 | + AuthenticationController.requireLogin(), 54 | + AuthorizationMiddleware.ensureUserCanWriteProjectContent, 55 | + ProjectUploadController.multerMiddleware, 56 | + ProjectUploadController.uploadFile 57 | + ) 58 | + } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /hotfix/2.0.2/2-read-only-access.patch: -------------------------------------------------------------------------------- 1 | --- TokenAccessHandler.js 2 | +++ TokenAccessHandler.js 3 | @@ -255,7 +255,7 @@ const TokenAccessHandler = { 4 | 5 | getV1DocPublishedInfo(token, callback) { 6 | // default to allowing access 7 | - if (!Settings.apis || !Settings.apis.v1) { 8 | + if (!Settings.apis.v1 || !Settings.apis.v1.url) { 9 | return callback(null, { allow: true }) 10 | } 11 | V1Api.request( 12 | -------------------------------------------------------------------------------- /hotfix/2.0.2/3-url-linking-1.patch: -------------------------------------------------------------------------------- 1 | --- Features.js 2 | +++ Features.js 3 | @@ -53,6 +53,8 @@ module.exports = Features = { 4 | return Settings.apis.references.url != null 5 | case 'saml': 6 | return Settings.enableSaml 7 | + case 'link-url': 8 | + return Settings.apis.linkedUrlProxy && Settings.apis.linkedUrlProxy.url 9 | default: 10 | throw new Error(`unknown feature: ${feature}`) 11 | } 12 | -------------------------------------------------------------------------------- /hotfix/2.0.2/4-url-linking-2.patch: -------------------------------------------------------------------------------- 1 | --- new-file-modal.pug 2 | +++ new-file-modal.pug 3 | @@ -21,11 +21,12 @@ script(type='text/ng-template', id='newFileModalTemplate') 4 | i.fa.fa-fw.fa-folder-open 5 | | 6 | | From Another Project 7 | - li(ng-class="type == 'url' ? 'active' : null") 8 | - a(href, ng-click="type = 'url'") 9 | - i.fa.fa-fw.fa-globe 10 | - | 11 | - | From External URL 12 | + if hasFeature('link-url') 13 | + li(ng-class="type == 'url' ? 'active' : null") 14 | + a(href, ng-click="type = 'url'") 15 | + i.fa.fa-fw.fa-globe 16 | + | 17 | + | From External URL 18 | != moduleIncludes("newFileModal:selector", locals) 19 | 20 | td(class="modal-new-file--body modal-new-file--body-{{type}}") 21 | -------------------------------------------------------------------------------- /hotfix/2.0.2/5-disable-analytics-1.patch: -------------------------------------------------------------------------------- 1 | --- AnalyticsController.js 2 | +++ AnalyticsController.js 3 | @@ -3,9 +3,13 @@ const Errors = require('../Errors/Errors') 4 | const AuthenticationController = require('../Authentication/AuthenticationController') 5 | const InstitutionsAPI = require('../Institutions/InstitutionsAPI') 6 | const GeoIpLookup = require('../../infrastructure/GeoIpLookup') 7 | +const Features = require('../../infrastructure/Features') 8 | 9 | module.exports = { 10 | updateEditingSession(req, res, next) { 11 | + if (!Features.hasFeature('analytics')) { 12 | + return res.send(204) 13 | + } 14 | const userId = AuthenticationController.getLoggedInUserId(req) 15 | const { projectId } = req.params 16 | let countryCode = null 17 | @@ -28,6 +32,9 @@ module.exports = { 18 | }, 19 | 20 | recordEvent(req, res, next) { 21 | + if (!Features.hasFeature('analytics')) { 22 | + return res.send(204) 23 | + } 24 | const userId = 25 | AuthenticationController.getLoggedInUserId(req) || req.sessionID 26 | AnalyticsManager.recordEvent(userId, req.params.event, req.body, error => 27 | -------------------------------------------------------------------------------- /hotfix/2.0.2/6-disable-analytics-2.patch: -------------------------------------------------------------------------------- 1 | --- Features.js 2 | +++ Features.js 3 | @@ -41,6 +41,7 @@ module.exports = Features = { 4 | case 'templates-server-pro': 5 | return Settings.overleaf == null 6 | case 'affiliations': 7 | + case 'analytics': 8 | // Checking both properties is needed for the time being to allow 9 | // enabling the feature in web-api and disabling in Server Pro 10 | // see https://github.com/overleaf/web-internal/pull/2127 11 | -------------------------------------------------------------------------------- /hotfix/2.0.2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM sharelatex/sharelatex:2.0.1 2 | 3 | 4 | # Patch 1: Fixes anonymous link sharing 5 | ADD 1-anon-upload.patch /var/www/sharelatex/web/app/src/Features/Uploads/1-anon-upload.patch 6 | RUN cd /var/www/sharelatex/web/app/src/Features/Uploads/ && \ 7 | patch < 1-anon-upload.patch 8 | 9 | 10 | # Patch 2: Fixes read-only access 11 | ADD 2-read-only-access.patch /var/www/sharelatex/web/app/src/Features/TokenAccess/3-read-only-access.patch 12 | RUN cd /var/www/sharelatex/web/app/src/Features/TokenAccess/ && \ 13 | patch < 3-read-only-access.patch 14 | 15 | 16 | # Patch 3: Fixes url linking 17 | ADD 3-url-linking-1.patch /var/www/sharelatex/web/app/src/infrastructure/6-url-linking-1.patch 18 | RUN cd /var/www/sharelatex/web/app/src/infrastructure/ && \ 19 | patch < 6-url-linking-1.patch 20 | ADD 4-url-linking-2.patch /var/www/sharelatex/web/app/views/project/editor/7-url-linking-2.patch 21 | RUN cd /var/www/sharelatex/web/app/views/project/editor/ && \ 22 | patch < 7-url-linking-2.patch 23 | 24 | 25 | # Patch 4: Disables analytics 26 | ADD 5-disable-analytics-1.patch /var/www/sharelatex/web/app/src/Features/Analytics/8-disable-analytics-1.patch 27 | RUN cd /var/www/sharelatex/web/app/src/Features/Analytics/ && \ 28 | patch < 8-disable-analytics-1.patch 29 | ADD 6-disable-analytics-2.patch /var/www/sharelatex/web/app/src/infrastructure/9-disable-analytics-2.patch 30 | RUN cd /var/www/sharelatex/web/app/src/infrastructure/ && \ 31 | patch < 9-disable-analytics-2.patch 32 | -------------------------------------------------------------------------------- /hotfix/2.1.1/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM sharelatex/sharelatex:2.1.0 2 | 3 | # Patch: defines recaptcha config to fix share-related issues 4 | # - https://github.com/overleaf/overleaf/issues/684 5 | ADD add-recaptcha-config.patch /etc/sharelatex/add-recaptcha-config.patch 6 | RUN cd /etc/sharelatex/ && \ 7 | patch < add-recaptcha-config.patch 8 | 9 | -------------------------------------------------------------------------------- /hotfix/2.1.1/add-recaptcha-config.patch: -------------------------------------------------------------------------------- 1 | --- a/settings.coffee 2 | +++ b/settings.coffee 3 | @@ -180,6 +180,11 @@ settings = 4 | # cookie with a secure flag (recommended). 5 | secureCookie: process.env["SHARELATEX_SECURE_COOKIE"]? 6 | 7 | + recaptcha: 8 | + disabled: 9 | + invite: true 10 | + register: true 11 | + 12 | # If you are running ShareLaTeX behind a proxy (like Apache, Nginx, etc) 13 | # then set this to true to allow it to correctly detect the forwarded IP 14 | # address and http/https protocol information. 15 | -------------------------------------------------------------------------------- /init_scripts/00_make_sharelatex_data_dirs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p /var/lib/sharelatex/data 5 | chown www-data:www-data /var/lib/sharelatex/data 6 | 7 | mkdir -p /var/lib/sharelatex/data/user_files 8 | chown www-data:www-data /var/lib/sharelatex/data/user_files 9 | 10 | mkdir -p /var/lib/sharelatex/data/compiles 11 | chown www-data:www-data /var/lib/sharelatex/data/compiles 12 | 13 | mkdir -p /var/lib/sharelatex/data/cache 14 | chown www-data:www-data /var/lib/sharelatex/data/cache 15 | 16 | mkdir -p /var/lib/sharelatex/data/template_files 17 | chown www-data:www-data /var/lib/sharelatex/data/template_files 18 | 19 | mkdir -p /var/lib/sharelatex/tmp/dumpFolder 20 | chown www-data:www-data /var/lib/sharelatex/tmp/dumpFolder 21 | 22 | mkdir -p /var/lib/sharelatex/tmp 23 | chown www-data:www-data /var/lib/sharelatex/tmp 24 | 25 | mkdir -p /var/lib/sharelatex/tmp/uploads 26 | chown www-data:www-data /var/lib/sharelatex/tmp/uploads 27 | 28 | mkdir -p /var/lib/sharelatex/tmp/dumpFolder 29 | chown www-data:www-data /var/lib/sharelatex/tmp/dumpFolder 30 | 31 | if [ ! -e "/var/lib/sharelatex/data/db.sqlite" ]; then 32 | touch /var/lib/sharelatex/data/db.sqlite 33 | fi 34 | 35 | chown www-data:www-data /var/lib/sharelatex/data/db.sqlite 36 | -------------------------------------------------------------------------------- /init_scripts/00_regen_sharelatex_secrets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e -o pipefail 3 | 4 | # generate secrets and defines them as environment variables 5 | # https://github.com/phusion/baseimage-docker#centrally-defining-your-own-environment-variables 6 | 7 | WEB_API_PASSWORD_FILE=/etc/container_environment/WEB_API_PASSWORD 8 | CRYPTO_RANDOM_FILE=/etc/container_environment/CRYPTO_RANDOM 9 | 10 | if [ ! -f "$WEB_API_PASSWORD_FILE" ] || [ ! -f "$CRYPTO_RANDOM_FILE" ]; then 11 | 12 | echo "generating random secrets" 13 | 14 | SECRET=$(dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 -w 0 | rev | cut -b 2- | rev | tr -d '\n+/') 15 | echo ${SECRET} > ${WEB_API_PASSWORD_FILE} 16 | 17 | SECRET=$(dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 -w 0 | rev | cut -b 2- | rev | tr -d '\n+/') 18 | echo ${SECRET} > ${CRYPTO_RANDOM_FILE} 19 | fi 20 | 21 | -------------------------------------------------------------------------------- /init_scripts/00_set_docker_host_ipaddress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e -o pipefail 3 | 4 | # See the bottom of http://stackoverflow.com/questions/24319662/from-inside-of-a-docker-container-how-do-i-connect-to-the-localhost-of-the-mach 5 | echo "`route -n | awk '/UG[ \t]/{print $2}'` dockerhost" >> /etc/hosts 6 | -------------------------------------------------------------------------------- /init_scripts/98_check_db_access.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "Checking can connect to mongo and redis" 5 | cd /var/www/sharelatex && grunt check:redis 6 | cd /var/www/sharelatex && grunt check:mongo 7 | echo "All checks passed" 8 | -------------------------------------------------------------------------------- /init_scripts/99_migrate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | which node 5 | which grunt 6 | ls -al /var/www/sharelatex/migrations 7 | cd /var/www/sharelatex && grunt migrate -v 8 | echo "All migrations finished" 9 | -------------------------------------------------------------------------------- /logrotate/sharelatex: -------------------------------------------------------------------------------- 1 | /var/log/sharelatex/*.log { 2 | daily 3 | missingok 4 | rotate 5 5 | compress 6 | copytruncate 7 | notifempty 8 | create 644 root adm 9 | } -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | daemon off; 2 | user www-data; 3 | worker_processes 4; 4 | pid /run/nginx.pid; 5 | 6 | events { 7 | worker_connections 768; 8 | # multi_accept on; 9 | } 10 | 11 | http { 12 | 13 | ## 14 | # Basic Settings 15 | ## 16 | 17 | sendfile on; 18 | tcp_nopush on; 19 | tcp_nodelay on; 20 | keepalive_timeout 65; 21 | types_hash_max_size 2048; 22 | # server_tokens off; 23 | 24 | # server_names_hash_bucket_size 64; 25 | # server_name_in_redirect off; 26 | 27 | include /etc/nginx/mime.types; 28 | default_type application/octet-stream; 29 | 30 | ## 31 | # Logging Settings 32 | ## 33 | 34 | access_log /var/log/nginx/access.log; 35 | error_log /var/log/nginx/error.log; 36 | 37 | ## 38 | # Gzip Settings 39 | ## 40 | 41 | gzip on; 42 | gzip_disable "msie6"; 43 | 44 | client_max_body_size 50m; 45 | 46 | # gzip_vary on; 47 | # gzip_proxied any; 48 | # gzip_comp_level 6; 49 | # gzip_buffers 16 8k; 50 | # gzip_http_version 1.1; 51 | # gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 52 | 53 | ## 54 | # nginx-naxsi config 55 | ## 56 | # Uncomment it if you installed nginx-naxsi 57 | ## 58 | 59 | #include /etc/nginx/naxsi_core.rules; 60 | 61 | ## 62 | # nginx-passenger config 63 | ## 64 | # Uncomment it if you installed nginx-passenger 65 | ## 66 | 67 | #passenger_root /usr; 68 | #passenger_ruby /usr/bin/ruby; 69 | 70 | ## 71 | # Virtual Host Configs 72 | ## 73 | 74 | include /etc/nginx/conf.d/*.conf; 75 | include /etc/nginx/sites-enabled/*; 76 | } 77 | -------------------------------------------------------------------------------- /nginx/sharelatex.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name _; # Catch all, see http://nginx.org/en/docs/http/server_names.html 4 | 5 | root /var/www/sharelatex/web/public/; 6 | 7 | location / { 8 | proxy_pass http://127.0.0.1:3000; 9 | proxy_http_version 1.1; 10 | proxy_set_header Upgrade $http_upgrade; 11 | proxy_set_header Connection "upgrade"; 12 | proxy_set_header X-Forwarded-Host $host; 13 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 14 | proxy_read_timeout 3m; 15 | proxy_send_timeout 3m; 16 | } 17 | 18 | location /socket.io { 19 | proxy_pass http://127.0.0.1:3026; 20 | proxy_http_version 1.1; 21 | proxy_set_header Upgrade $http_upgrade; 22 | proxy_set_header Connection "upgrade"; 23 | proxy_set_header X-Forwarded-Host $host; 24 | proxy_set_header X-Forwarded-Proto $scheme; 25 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 26 | proxy_read_timeout 3m; 27 | proxy_send_timeout 3m; 28 | } 29 | 30 | location /stylesheets { 31 | expires 1y; 32 | } 33 | 34 | location /minjs { 35 | expires 1y; 36 | } 37 | 38 | location /img { 39 | expires 1y; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /runit/chat-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | 4 | NODE_PARAMS="" 5 | if [ "$DEBUG_NODE" == "true" ]; then 6 | echo "running debug - chat" 7 | NODE_PARAMS="--inspect=0.0.0.0:30100" 8 | fi 9 | 10 | exec /sbin/setuser www-data /usr/bin/node $NODE_PARAMS /var/www/sharelatex/chat/app.js >> /var/log/sharelatex/chat.log 2>&1 11 | -------------------------------------------------------------------------------- /runit/clsi-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | 4 | NODE_PARAMS="" 5 | if [ "$DEBUG_NODE" == "true" ]; then 6 | echo "running debug - clsi" 7 | NODE_PARAMS="--inspect=0.0.0.0:30130" 8 | fi 9 | 10 | # Set permissions on docker.sock if present, 11 | # To enable sibling-containers (see entrypoint.sh in clsi project) 12 | if [ -e '/var/run/docker.sock' ]; then 13 | echo ">> Setting permissions on docker socket" 14 | DOCKER_GROUP=$(stat -c '%g' /var/run/docker.sock) 15 | groupadd --non-unique --gid ${DOCKER_GROUP} dockeronhost 16 | usermod -aG dockeronhost www-data 17 | fi 18 | 19 | # Copies over CSLI synctex to the host mounted volume, so it 20 | # can be subsequently mounted in TexLive containers on Sandbox Compilation 21 | SYNCTEX=/var/lib/sharelatex/bin/synctex 22 | if [ ! -f "$SYNCTEX" ]; then 23 | if [ "$DISABLE_SYNCTEX_BINARY_COPY" == "true" ]; then 24 | echo ">> Copy of synctex executable disabled by DISABLE_SYNCTEX_BINARY_COPY flag, feature may not work" 25 | else 26 | echo ">> Copying synctex executable to the host" 27 | mkdir -p $(dirname $SYNCTEX ) 28 | cp /var/www/sharelatex/clsi/bin/synctex $SYNCTEX 29 | fi 30 | fi 31 | 32 | exec /sbin/setuser www-data /usr/bin/node $NODE_PARAMS /var/www/sharelatex/clsi/app.js >> /var/log/sharelatex/clsi.log 2>&1 33 | -------------------------------------------------------------------------------- /runit/contacts-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | 4 | NODE_PARAMS="" 5 | if [ "$DEBUG_NODE" == "true" ]; then 6 | echo "running debug - contacts" 7 | NODE_PARAMS="--inspect=0.0.0.0:30360" 8 | fi 9 | 10 | exec /sbin/setuser www-data /usr/bin/node $NODE_PARAMS /var/www/sharelatex/contacts/app.js >> /var/log/sharelatex/contacts 2>&1 11 | -------------------------------------------------------------------------------- /runit/docstore-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | 4 | NODE_PARAMS="" 5 | if [ "$DEBUG_NODE" == "true" ]; then 6 | echo "running debug - docstore" 7 | NODE_PARAMS="--inspect=0.0.0.0:30160" 8 | fi 9 | 10 | exec /sbin/setuser www-data /usr/bin/node $NODE_PARAMS /var/www/sharelatex/docstore/app.js >> /var/log/sharelatex/docstore.log 2>&1 11 | -------------------------------------------------------------------------------- /runit/document-updater-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | 4 | NODE_PARAMS="" 5 | if [ "$DEBUG_NODE" == "true" ]; then 6 | echo "running debug - document updater" 7 | NODE_PARAMS="--inspect=0.0.0.0:30030" 8 | fi 9 | 10 | exec /sbin/setuser www-data /usr/bin/node $NODE_PARAMS /var/www/sharelatex/document-updater/app.js >> /var/log/sharelatex/document-updater.log 2>&1 11 | -------------------------------------------------------------------------------- /runit/filestore-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | exec /sbin/setuser www-data /usr/bin/node /var/www/sharelatex/filestore/app.js >> /var/log/sharelatex/filestore.log 2>&1 4 | -------------------------------------------------------------------------------- /runit/nginx/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exec nginx -------------------------------------------------------------------------------- /runit/notifications-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | 4 | NODE_PARAMS="" 5 | if [ "$DEBUG_NODE" == "true" ]; then 6 | echo "running debug - notifications" 7 | NODE_PARAMS="--inspect=0.0.0.0:30420" 8 | fi 9 | 10 | exec /sbin/setuser www-data /usr/bin/node $NODE_PARAMS /var/www/sharelatex/notifications/app.js >> /var/log/sharelatex/notifications.log 2>&1 11 | -------------------------------------------------------------------------------- /runit/real-time-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | exec /sbin/setuser www-data /usr/bin/node /var/www/sharelatex/real-time/app.js >> /var/log/sharelatex/real-time.log 2>&1 4 | -------------------------------------------------------------------------------- /runit/spelling-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | 4 | NODE_PARAMS="" 5 | if [ "$DEBUG_NODE" == "true" ]; then 6 | echo "running debug - spelling" 7 | NODE_PARAMS="--inspect=0.0.0.0:30050" 8 | fi 9 | 10 | exec /sbin/setuser www-data /usr/bin/node $NODE_PARAMS /var/www/sharelatex/spelling/app.js >> /var/log/sharelatex/spelling.log 2>&1 11 | -------------------------------------------------------------------------------- /runit/tags-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | 4 | NODE_PARAMS="" 5 | if [ "$DEBUG_NODE" == "true" ]; then 6 | echo "running debug - tags" 7 | NODE_PARAMS="--inspect=0.0.0.0:30120" 8 | fi 9 | 10 | exec /sbin/setuser www-data /usr/bin/node $NODE_PARAMS /var/www/sharelatex/tags/app.js >> /var/log/sharelatex/tags.log 2>&1 11 | -------------------------------------------------------------------------------- /runit/track-changes-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | 4 | NODE_PARAMS="" 5 | if [ "$DEBUG_NODE" == "true" ]; then 6 | echo "running debug - track-changes" 7 | NODE_PARAMS="--inspect=0.0.0.0:30150" 8 | fi 9 | 10 | exec /sbin/setuser www-data /usr/bin/node $NODE_PARAMS /var/www/sharelatex/track-changes/app.js >> /var/log/sharelatex/track-changes.log 2>&1 11 | -------------------------------------------------------------------------------- /runit/web-sharelatex/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee 3 | 4 | NODE_PARAMS="" 5 | if [ "$DEBUG_NODE" == "true" ]; then 6 | echo "running debug - web" 7 | NODE_PARAMS="--inspect=0.0.0.0:40000" 8 | fi 9 | 10 | exec /sbin/setuser www-data /usr/bin/node $NODE_PARAMS /var/www/sharelatex/web/app.js >> /var/log/sharelatex/web.log 2>&1 11 | -------------------------------------------------------------------------------- /services.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | 3 | [{ 4 | name: "web", 5 | repo: "https://github.com/sharelatex/web-sharelatex.git", 6 | version: "master" 7 | }, { 8 | name: "real-time", 9 | repo: "https://github.com/sharelatex/real-time-sharelatex.git", 10 | version: "master" 11 | }, { 12 | name: "document-updater", 13 | repo: "https://github.com/sharelatex/document-updater-sharelatex.git", 14 | version: "master" 15 | }, { 16 | name: "clsi", 17 | repo: "https://github.com/sharelatex/clsi-sharelatex.git", 18 | version: "master" 19 | }, { 20 | name: "filestore", 21 | repo: "https://github.com/sharelatex/filestore-sharelatex.git", 22 | version: "master" 23 | }, { 24 | name: "track-changes", 25 | repo: "https://github.com/sharelatex/track-changes-sharelatex.git", 26 | version: "master" 27 | }, { 28 | name: "docstore", 29 | repo: "https://github.com/sharelatex/docstore-sharelatex.git", 30 | version: "master" 31 | }, { 32 | name: "chat", 33 | repo: "https://github.com/sharelatex/chat-sharelatex.git", 34 | version: "master" 35 | }, { 36 | name: "tags", 37 | repo: "https://github.com/sharelatex/tags-sharelatex.git", 38 | version: "master" 39 | }, { 40 | name: "spelling", 41 | repo: "https://github.com/sharelatex/spelling-sharelatex.git", 42 | version: "master" 43 | }, { 44 | name: "contacts", 45 | repo: "https://github.com/sharelatex/contacts-sharelatex.git", 46 | version: "sk-update-mongojs" 47 | }, { 48 | name: "notifications", 49 | repo: "https://github.com/sharelatex/notifications-sharelatex.git", 50 | version: "master" 51 | }] 52 | -------------------------------------------------------------------------------- /settings.coffee: -------------------------------------------------------------------------------- 1 | Path = require('path') 2 | 3 | # These credentials are used for authenticating api requests 4 | # between services that may need to go over public channels 5 | httpAuthUser = "sharelatex" 6 | httpAuthPass = process.env["WEB_API_PASSWORD"] 7 | httpAuthUsers = {} 8 | httpAuthUsers[httpAuthUser] = httpAuthPass 9 | 10 | parse = (option)-> 11 | if option? 12 | try 13 | opt = JSON.parse(option) 14 | return opt 15 | catch err 16 | console.error "problem parsing #{option}, invalid JSON" 17 | return undefined 18 | 19 | 20 | DATA_DIR = '/var/lib/sharelatex/data' 21 | TMP_DIR = '/var/lib/sharelatex/tmp' 22 | 23 | settings = 24 | 25 | brandPrefix: "" 26 | 27 | allowAnonymousReadAndWriteSharing: 28 | process.env['SHARELATEX_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING'] == 'true' 29 | 30 | # Databases 31 | # --------- 32 | 33 | # ShareLaTeX's main persistant data store is MongoDB (http://www.mongodb.org/) 34 | # Documentation about the URL connection string format can be found at: 35 | # 36 | # http://docs.mongodb.org/manual/reference/connection-string/ 37 | # 38 | # The following works out of the box with Mongo's default settings: 39 | mongo: 40 | url : process.env["SHARELATEX_MONGO_URL"] or 'mongodb://dockerhost/sharelatex' 41 | 42 | # Redis is used in ShareLaTeX for high volume queries, like real-time 43 | # editing, and session management. 44 | # 45 | # The following config will work with Redis's default settings: 46 | redis: 47 | web: redisConfig = 48 | host: process.env["SHARELATEX_REDIS_HOST"] or "dockerhost" 49 | port: process.env["SHARELATEX_REDIS_PORT"] or "6379" 50 | password: process.env["SHARELATEX_REDIS_PASS"] or "" 51 | key_schema: 52 | # document-updater 53 | blockingKey: ({doc_id}) -> "Blocking:#{doc_id}" 54 | docLines: ({doc_id}) -> "doclines:#{doc_id}" 55 | docOps: ({doc_id}) -> "DocOps:#{doc_id}" 56 | docVersion: ({doc_id}) -> "DocVersion:#{doc_id}" 57 | docHash: ({doc_id}) -> "DocHash:#{doc_id}" 58 | projectKey: ({doc_id}) -> "ProjectId:#{doc_id}" 59 | docsInProject: ({project_id}) -> "DocsIn:#{project_id}" 60 | ranges: ({doc_id}) -> "Ranges:#{doc_id}" 61 | # document-updater:realtime 62 | pendingUpdates: ({doc_id}) -> "PendingUpdates:#{doc_id}" 63 | # document-updater:history 64 | uncompressedHistoryOps: ({doc_id}) -> "UncompressedHistoryOps:#{doc_id}" 65 | docsWithHistoryOps: ({project_id}) -> "DocsWithHistoryOps:#{project_id}" 66 | # document-updater:lock 67 | blockingKey: ({doc_id}) -> "Blocking:#{doc_id}" 68 | # track-changes:lock 69 | historyLock: ({doc_id}) -> "HistoryLock:#{doc_id}" 70 | historyIndexLock: ({project_id}) -> "HistoryIndexLock:#{project_id}" 71 | # track-chanegs:history 72 | uncompressedHistoryOps: ({doc_id}) -> "UncompressedHistoryOps:#{doc_id}" 73 | docsWithHistoryOps: ({project_id}) -> "DocsWithHistoryOps:#{project_id}" 74 | # realtime 75 | clientsInProject: ({project_id}) -> "clients_in_project:#{project_id}" 76 | connectedUser: ({project_id, client_id})-> "connected_user:#{project_id}:#{client_id}" 77 | fairy: redisConfig 78 | # track-changes and document-updater 79 | realtime: redisConfig 80 | documentupdater: redisConfig 81 | lock: redisConfig 82 | history: redisConfig 83 | websessions: redisConfig 84 | api: redisConfig 85 | pubsub: redisConfig 86 | project_history: redisConfig 87 | 88 | # The compile server (the clsi) uses a SQL database to cache files and 89 | # meta-data. sqllite is the default, and the load is low enough that this will 90 | # be fine in production (we use sqllite at sharelatex.com). 91 | # 92 | # If you want to configure a different database, see the Sequelize documentation 93 | # for available options: 94 | # 95 | # https://github.com/sequelize/sequelize/wiki/API-Reference-Sequelize#example-usage 96 | # 97 | mysql: 98 | clsi: 99 | database: "clsi" 100 | username: "clsi" 101 | password: "" 102 | dialect: "sqlite" 103 | storage: Path.join(DATA_DIR, "db.sqlite") 104 | 105 | # File storage 106 | # ------------ 107 | 108 | # ShareLaTeX can store binary files like images either locally or in Amazon 109 | # S3. The default is locally: 110 | filestore: 111 | backend: "fs" 112 | stores: 113 | user_files: Path.join(DATA_DIR, "user_files") 114 | template_files: Path.join(DATA_DIR, "template_files") 115 | 116 | # To use Amazon S3 as a storage backend, comment out the above config, and 117 | # uncomment the following, filling in your key, secret, and bucket name: 118 | # 119 | # filestore: 120 | # backend: "s3" 121 | # stores: 122 | # user_files: "BUCKET_NAME" 123 | # s3: 124 | # key: "AWS_KEY" 125 | # secret: "AWS_SECRET" 126 | # 127 | 128 | trackchanges: 129 | continueOnError: true 130 | 131 | # Local disk caching 132 | # ------------------ 133 | path: 134 | # If we ever need to write something to disk (e.g. incoming requests 135 | # that need processing but may be too big for memory), then write 136 | # them to disk here: 137 | dumpFolder: Path.join(TMP_DIR, "dumpFolder") 138 | # Where to write uploads before they are processed 139 | uploadFolder: Path.join(TMP_DIR, "uploads") 140 | # Where to write the project to disk before running LaTeX on it 141 | compilesDir: Path.join(DATA_DIR, "compiles") 142 | # Where to cache downloaded URLs for the CLSI 143 | clsiCacheDir: Path.join(DATA_DIR, "cache") 144 | 145 | # Server Config 146 | # ------------- 147 | 148 | # Where your instance of ShareLaTeX can be found publicly. This is used 149 | # when emails are sent out and in generated links: 150 | siteUrl: siteUrl = process.env["SHARELATEX_SITE_URL"] or 'http://localhost' 151 | 152 | # The name this is used to describe your ShareLaTeX Installation 153 | appName: process.env["SHARELATEX_APP_NAME"] or "ShareLaTeX (Community Edition)" 154 | 155 | restrictInvitesToExistingAccounts: process.env["SHARELATEX_RESTRICT_INVITES_TO_EXISTING_ACCOUNTS"] == 'true' 156 | 157 | nav: 158 | title: process.env["SHARELATEX_NAV_TITLE"] or process.env["SHARELATEX_APP_NAME"] or "ShareLaTeX Community Edition" 159 | 160 | 161 | # The email address which users will be directed to as the main point of 162 | # contact for this installation of ShareLaTeX. 163 | adminEmail: process.env["SHARELATEX_ADMIN_EMAIL"] or "placeholder@example.com" 164 | 165 | # If provided, a sessionSecret is used to sign cookies so that they cannot be 166 | # spoofed. This is recommended. 167 | security: 168 | sessionSecret: process.env["SHARELATEX_SESSION_SECRET"] or process.env["CRYPTO_RANDOM"] 169 | 170 | # These credentials are used for authenticating api requests 171 | # between services that may need to go over public channels 172 | httpAuthUsers: httpAuthUsers 173 | 174 | # Should javascript assets be served minified or not. 175 | useMinifiedJs: true 176 | 177 | # Should static assets be sent with a header to tell the browser to cache 178 | # them. This should be false in development where changes are being made, 179 | # but should be set to true in production. 180 | cacheStaticAssets: true 181 | 182 | # If you are running ShareLaTeX over https, set this to true to send the 183 | # cookie with a secure flag (recommended). 184 | secureCookie: process.env["SHARELATEX_SECURE_COOKIE"]? 185 | 186 | # If you are running ShareLaTeX behind a proxy (like Apache, Nginx, etc) 187 | # then set this to true to allow it to correctly detect the forwarded IP 188 | # address and http/https protocol information. 189 | 190 | behindProxy: process.env["SHARELATEX_BEHIND_PROXY"] or false 191 | 192 | i18n: 193 | subdomainLang: 194 | www: {lngCode:process.env["SHARELATEX_SITE_LANGUAGE"] or "en", url: siteUrl} 195 | defaultLng: process.env["SHARELATEX_SITE_LANGUAGE"] or "en" 196 | 197 | apis: 198 | web: 199 | url: "http://localhost:3000" 200 | user: httpAuthUser 201 | pass: httpAuthPass 202 | project_history: 203 | enabled: false 204 | references:{} 205 | notifications:undefined 206 | 207 | defaultFeatures: 208 | collaborators: -1 209 | dropbox: true 210 | versioning: true 211 | compileTimeout: 180 212 | compileGroup: "standard" 213 | trackChanges: true 214 | templates: true 215 | references: true 216 | 217 | ## OPTIONAL CONFIGERABLE SETTINGS 218 | 219 | if process.env["SHARELATEX_LEFT_FOOTER"]? 220 | try 221 | settings.nav.left_footer = JSON.parse(process.env["SHARELATEX_LEFT_FOOTER"]) 222 | catch e 223 | console.error("could not parse SHARELATEX_LEFT_FOOTER, not valid JSON") 224 | 225 | if process.env["SHARELATEX_RIGHT_FOOTER"]? 226 | settings.nav.right_footer = process.env["SHARELATEX_RIGHT_FOOTER"] 227 | try 228 | settings.nav.right_footer = JSON.parse(process.env["SHARELATEX_RIGHT_FOOTER"]) 229 | catch e 230 | console.error("could not parse SHARELATEX_RIGHT_FOOTER, not valid JSON") 231 | 232 | if process.env["SHARELATEX_HEADER_IMAGE_URL"]? 233 | settings.nav.custom_logo = process.env["SHARELATEX_HEADER_IMAGE_URL"] 234 | 235 | if process.env["SHARELATEX_HEADER_NAV_LINKS"]? 236 | console.error """ 237 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 238 | # 239 | # WARNING: SHARELATEX_HEADER_NAV_LINKS is no longer supported 240 | # See https://github.com/sharelatex/sharelatex/wiki/Configuring-Headers,-Footers-&-Logo 241 | # 242 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 243 | """ 244 | 245 | if process.env["SHARELATEX_HEADER_EXTRAS"]? 246 | try 247 | settings.nav.header_extras = JSON.parse(process.env["SHARELATEX_HEADER_EXTRAS"]) 248 | catch e 249 | console.error("could not parse SHARELATEX_HEADER_EXTRAS, not valid JSON") 250 | 251 | 252 | 253 | # Sending Email 254 | # ------------- 255 | # 256 | # You must configure a mail server to be able to send invite emails from 257 | # ShareLaTeX. The config settings are passed to nodemailer. See the nodemailer 258 | # documentation for available options: 259 | # 260 | # http://www.nodemailer.com/docs/transports 261 | 262 | 263 | if process.env["SHARELATEX_EMAIL_FROM_ADDRESS"]? 264 | 265 | settings.email = 266 | fromAddress: process.env["SHARELATEX_EMAIL_FROM_ADDRESS"] 267 | replyTo: process.env["SHARELATEX_EMAIL_REPLY_TO"] or "" 268 | driver: process.env["SHARELATEX_EMAIL_DRIVER"] 269 | parameters: 270 | #AWS Creds 271 | AWSAccessKeyID: process.env["SHARELATEX_EMAIL_AWS_SES_ACCESS_KEY_ID"] 272 | AWSSecretKey: process.env["SHARELATEX_EMAIL_AWS_SES_SECRET_KEY"] 273 | 274 | #SMTP Creds 275 | host: process.env["SHARELATEX_EMAIL_SMTP_HOST"] 276 | port: process.env["SHARELATEX_EMAIL_SMTP_PORT"], 277 | secure: parse(process.env["SHARELATEX_EMAIL_SMTP_SECURE"]) 278 | ignoreTLS: parse(process.env["SHARELATEX_EMAIL_SMTP_IGNORE_TLS"]) 279 | 280 | textEncoding: process.env["SHARELATEX_EMAIL_TEXT_ENCODING"] 281 | templates: 282 | customFooter: process.env["SHARELATEX_CUSTOM_EMAIL_FOOTER"] 283 | 284 | if process.env["SHARELATEX_EMAIL_SMTP_USER"]? or process.env["SHARELATEX_EMAIL_SMTP_PASS"]? 285 | settings.email.parameters.auth = 286 | user: process.env["SHARELATEX_EMAIL_SMTP_USER"] 287 | pass: process.env["SHARELATEX_EMAIL_SMTP_PASS"] 288 | 289 | if process.env["SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH"]? 290 | settings.email.parameters.tls = 291 | rejectUnauthorized: parse(process.env["SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH"]) 292 | 293 | 294 | # i18n 295 | if process.env["SHARELATEX_LANG_DOMAIN_MAPPING"]? 296 | 297 | settings.i18n.subdomainLang = parse(process.env["SHARELATEX_LANG_DOMAIN_MAPPING"]) 298 | 299 | # Password Settings 300 | # ----------- 301 | # These restrict the passwords users can use when registering 302 | # opts are from http://antelle.github.io/passfield 303 | if process.env["SHARELATEX_PASSWORD_VALIDATION_PATTERN"] or process.env["SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH"] or process.env["SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH"] 304 | 305 | settings.passwordStrengthOptions = 306 | pattern: process.env["SHARELATEX_PASSWORD_VALIDATION_PATTERN"] or "aA$3" 307 | length: {min:process.env["SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH"] or 8, max: process.env["SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH"] or 150} 308 | 309 | 310 | 311 | 312 | ####################### 313 | # ShareLaTeX Server Pro 314 | ####################### 315 | 316 | if parse(process.env["SHARELATEX_IS_SERVER_PRO"]) == true 317 | settings.bypassPercentageRollouts = true 318 | settings.apis.references = 319 | url: "http://localhost:3040" 320 | 321 | 322 | # LDAP - SERVER PRO ONLY 323 | # ---------- 324 | 325 | if process.env["SHARELATEX_LDAP_HOST"] 326 | console.error """ 327 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 328 | # 329 | # WARNING: The LDAP configuration format has changed in version 0.5.1 330 | # See https://github.com/sharelatex/sharelatex/wiki/Server-Pro:-LDAP-Config 331 | # 332 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 333 | """ 334 | 335 | if process.env["SHARELATEX_LDAP_URL"] 336 | settings.externalAuth = true 337 | settings.ldap = 338 | emailAtt: process.env["SHARELATEX_LDAP_EMAIL_ATT"] 339 | nameAtt: process.env["SHARELATEX_LDAP_NAME_ATT"] 340 | lastNameAtt: process.env["SHARELATEX_LDAP_LAST_NAME_ATT"] 341 | updateUserDetailsOnLogin: process.env["SHARELATEX_LDAP_UPDATE_USER_DETAILS_ON_LOGIN"] == 'true' 342 | placeholder: process.env["SHARELATEX_LDAP_PLACEHOLDER"] 343 | server: 344 | url: process.env["SHARELATEX_LDAP_URL"] 345 | bindDn: process.env["SHARELATEX_LDAP_BIND_DN"] 346 | bindCredentials: process.env["SHARELATEX_LDAP_BIND_CREDENTIALS"] 347 | bindProperty: process.env["SHARELATEX_LDAP_BIND_PROPERTY"] 348 | searchBase: process.env["SHARELATEX_LDAP_SEARCH_BASE"] 349 | searchScope: process.env["SHARELATEX_LDAP_SEARCH_SCOPE"] 350 | searchFilter: process.env["SHARELATEX_LDAP_SEARCH_FILTER"] 351 | searchAttributes: ( 352 | if _ldap_search_attribs = process.env["SHARELATEX_LDAP_SEARCH_ATTRIBUTES"] 353 | try 354 | JSON.parse(_ldap_search_attribs) 355 | catch e 356 | console.error "could not parse SHARELATEX_LDAP_SEARCH_ATTRIBUTES" 357 | else 358 | undefined 359 | ) 360 | groupDnProperty: process.env["SHARELATEX_LDAP_GROUP_DN_PROPERTY"] 361 | groupSearchBase: process.env["SHARELATEX_LDAP_GROUP_SEARCH_BASE"] 362 | groupSearchScope: process.env["SHARELATEX_LDAP_GROUP_SEARCH_SCOPE"] 363 | groupSearchFilter: process.env["SHARELATEX_LDAP_GROUP_SEARCH_FILTER"] 364 | groupSearchAttributes: ( 365 | if _ldap_group_search_attribs = process.env["SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES"] 366 | try 367 | JSON.parse(_ldap_group_search_attribs) 368 | catch e 369 | console.error "could not parse SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES" 370 | else 371 | undefined 372 | ) 373 | cache: process.env["SHARELATEX_LDAP_CACHE"] == 'true' 374 | timeout: ( 375 | if _ldap_timeout = process.env["SHARELATEX_LDAP_TIMEOUT"] 376 | try 377 | parseInt(_ldap_timeout) 378 | catch e 379 | console.error "Cannot parse SHARELATEX_LDAP_TIMEOUT" 380 | else 381 | undefined 382 | ) 383 | connectTimeout: ( 384 | if _ldap_connect_timeout = process.env["SHARELATEX_LDAP_CONNECT_TIMEOUT"] 385 | try 386 | parseInt(_ldap_connect_timeout) 387 | catch e 388 | console.error "Cannot parse SHARELATEX_LDAP_CONNECT_TIMEOUT" 389 | else 390 | undefined 391 | ) 392 | 393 | if process.env["SHARELATEX_LDAP_TLS_OPTS_CA_PATH"] 394 | try 395 | ca = JSON.parse(process.env["SHARELATEX_LDAP_TLS_OPTS_CA_PATH"]) 396 | catch e 397 | console.error "could not parse SHARELATEX_LDAP_TLS_OPTS_CA_PATH, invalid JSON" 398 | 399 | if typeof(ca) == 'string' 400 | ca_paths = [ca] 401 | else if typeof(ca) == 'object' && ca?.length? 402 | ca_paths = ca 403 | else 404 | console.error "problem parsing SHARELATEX_LDAP_TLS_OPTS_CA_PATH" 405 | 406 | settings.ldap.server.tlsOptions = 407 | rejectUnauthorized: process.env["SHARELATEX_LDAP_TLS_OPTS_REJECT_UNAUTH"] == "true" 408 | ca:ca_paths # e.g.'/etc/ldap/ca_certs.pem' 409 | 410 | 411 | 412 | 413 | 414 | if process.env["SHARELATEX_SAML_ENTRYPOINT"] 415 | # NOTE: see https://github.com/bergie/passport-saml/blob/master/README.md for docs of `server` options 416 | settings.externalAuth = true 417 | settings.saml = 418 | updateUserDetailsOnLogin: process.env["SHARELATEX_SAML_UPDATE_USER_DETAILS_ON_LOGIN"] == 'true' 419 | identityServiceName: process.env["SHARELATEX_SAML_IDENTITY_SERVICE_NAME"] 420 | emailField: process.env["SHARELATEX_SAML_EMAIL_FIELD"] || process.env["SHARELATEX_SAML_EMAIL_FIELD_NAME"] 421 | firstNameField: process.env["SHARELATEX_SAML_FIRST_NAME_FIELD"] 422 | lastNameField: process.env["SHARELATEX_SAML_LAST_NAME_FIELD"] 423 | server: 424 | # strings 425 | entryPoint: process.env["SHARELATEX_SAML_ENTRYPOINT"] 426 | callbackUrl: process.env["SHARELATEX_SAML_CALLBACK_URL"] 427 | issuer: process.env["SHARELATEX_SAML_ISSUER"] 428 | decryptionPvk: process.env["SHARELATEX_SAML_DECRYPTION_PVK"] 429 | signatureAlgorithm: process.env["SHARELATEX_SAML_SIGNATURE_ALGORITHM"] 430 | identifierFormat: process.env["SHARELATEX_SAML_IDENTIFIER_FORMAT"] 431 | attributeConsumingServiceIndex: process.env["SHARELATEX_SAML_ATTRIBUTE_CONSUMING_SERVICE_INDEX"] 432 | authnContext: process.env["SHARELATEX_SAML_AUTHN_CONTEXT"] 433 | authnRequestBinding: process.env["SHARELATEX_SAML_AUTHN_REQUEST_BINDING"] 434 | validateInResponseTo: process.env["SHARELATEX_SAML_VALIDATE_IN_RESPONSE_TO"] 435 | cacheProvider: process.env["SHARELATEX_SAML_CACHE_PROVIDER"] 436 | logoutUrl: process.env["SHARELATEX_SAML_LOGOUT_URL"] 437 | logoutCallbackUrl: process.env["SHARELATEX_SAML_LOGOUT_CALLBACK_URL"] 438 | disableRequestedAuthnContext: process.env["SHARELATEX_SAML_DISABLE_REQUESTED_AUTHN_CONTEXT"] == 'true' 439 | forceAuthn: process.env["SHARELATEX_SAML_FORCE_AUTHN"] == 'true' 440 | skipRequestCompression: process.env["SHARELATEX_SAML_SKIP_REQUEST_COMPRESSION"] == 'true' 441 | acceptedClockSkewMs: ( 442 | if _saml_skew = process.env["SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS"] 443 | try 444 | parseInt(_saml_skew) 445 | catch e 446 | console.error "Cannot parse SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS" 447 | else 448 | undefined 449 | ) 450 | requestIdExpirationPeriodMs: ( 451 | if _saml_exiration = process.env["SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS"] 452 | try 453 | parseInt(_saml_expiration) 454 | catch e 455 | console.error "Cannot parse SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS" 456 | else 457 | undefined 458 | ) 459 | additionalParams: ( 460 | if _saml_additionalParams = process.env["SHARELATEX_SAML_ADDITIONAL_PARAMS"] 461 | try 462 | JSON.parse(_saml_additionalParams) 463 | catch e 464 | console.error "Cannot parse SHARELATEX_SAML_ADDITIONAL_PARAMS" 465 | else 466 | undefined 467 | ) 468 | additionalAuthorizeParams: ( 469 | if _saml_additionalAuthorizeParams = process.env["SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS"] 470 | try 471 | JSON.parse(_saml_additionalAuthorizeParams ) 472 | catch e 473 | console.error "Cannot parse SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS" 474 | else 475 | undefined 476 | ) 477 | additionalLogoutParams: ( 478 | if _saml_additionalLogoutParams = process.env["SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS"] 479 | try 480 | JSON.parse(_saml_additionalLogoutParams ) 481 | catch e 482 | console.error "Cannot parse SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS" 483 | else 484 | undefined 485 | ) 486 | 487 | # SHARELATEX_SAML_CERT cannot be empty 488 | # https://github.com/bergie/passport-saml/commit/f6b1c885c0717f1083c664345556b535f217c102 489 | if process.env["SHARELATEX_SAML_CERT"] 490 | settings.saml.server.cert = process.env["SHARELATEX_SAML_CERT"] 491 | settings.saml.server.privateCert = process.env["SHARELATEX_SAML_PRIVATE_CERT"] 492 | 493 | # Compiler 494 | # -------- 495 | if process.env["SANDBOXED_COMPILES"] == "true" 496 | settings.clsi = 497 | dockerRunner: true 498 | docker: 499 | image: process.env["TEX_LIVE_DOCKER_IMAGE"] 500 | env: 501 | HOME: "/tmp" 502 | PATH: process.env["COMPILER_PATH"] or "/usr/local/texlive/2015/bin/x86_64-linux:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 503 | user: "www-data" 504 | 505 | if !settings.path? 506 | settings.path = {} 507 | settings.path.synctexBaseDir = () -> "/compile" 508 | if process.env['SANDBOXED_COMPILES_SIBLING_CONTAINERS'] == 'true' 509 | console.log("Using sibling containers for sandboxed compiles") 510 | if process.env['SANDBOXED_COMPILES_HOST_DIR'] 511 | settings.path.sandboxedCompilesHostDir = process.env['SANDBOXED_COMPILES_HOST_DIR'] 512 | else 513 | console.error('Sibling containers, but SANDBOXED_COMPILES_HOST_DIR not set') 514 | 515 | 516 | # Templates 517 | # --------- 518 | if process.env["SHARELATEX_TEMPLATES_USER_ID"] 519 | settings.templates = 520 | mountPointUrl: "/templates" 521 | user_id: process.env["SHARELATEX_TEMPLATES_USER_ID"] 522 | 523 | settings.templateLinks = parse(process.env["SHARELATEX_NEW_PROJECT_TEMPLATE_LINKS"]) 524 | 525 | 526 | # /Learn 527 | # ------- 528 | if process.env["SHARELATEX_PROXY_LEARN"]? 529 | settings.proxyLearn = parse(process.env["SHARELATEX_PROXY_LEARN"]) 530 | 531 | 532 | # /References 533 | # ----------- 534 | if process.env["SHARELATEX_ELASTICSEARCH_URL"]? 535 | settings.references.elasticsearch = 536 | host: process.env["SHARELATEX_ELASTICSEARCH_URL"] 537 | 538 | 539 | # With lots of incoming and outgoing HTTP connections to different services, 540 | # sometimes long running, it is a good idea to increase the default number 541 | # of sockets that Node will hold open. 542 | http = require('http') 543 | http.globalAgent.maxSockets = 300 544 | https = require('https') 545 | https.globalAgent.maxSockets = 300 546 | 547 | module.exports = settings 548 | 549 | --------------------------------------------------------------------------------