├── - ├── .env.dist ├── .git.bfg-report └── 2017-11-13 │ └── 14-44-35 │ └── protected-dirt │ └── d2d906a9-HEAD.csv ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── docker-compose.yml └── nginx ├── Dockerfile ├── README.md ├── conf ├── nginx.conf └── tls.conf ├── config.py ├── letsencrypt.py ├── nginx.conf.fallback ├── start.py └── start.sh /-: -------------------------------------------------------------------------------- 1 | .env 2 | .DS_Store 3 | .git.bfg-report 4 | -------------------------------------------------------------------------------- /.env.dist: -------------------------------------------------------------------------------- 1 | # Mailu main configuration file 2 | # 3 | # Most configuration variables can be modified through the Web interface, 4 | # these few settings must however be configured before starting the mail 5 | # server and require a restart upon change. 6 | 7 | ################################### 8 | # Common configuration variables 9 | ################################### 10 | 11 | # Set this to the path where Mailu data and configuration is stored 12 | # Mac users: Change to a Docker accessible folder 13 | ROOT=/opt/tellform_data 14 | 15 | # Set to what environment you will be running TellForm in (production or development) 16 | NODE_ENV=development 17 | 18 | # Set to a randomly generated 16 bytes string 19 | SECRET_KEY=ChangeMeChangeMe 20 | 21 | # URI of Mongo database that TellForm will connect to 22 | #DO NOT CHANGE 23 | MONGODB_URI=mongodb://mongo/tellform 24 | 25 | # URL Redis server that TellForm will connect to 26 | #DO NOT CHANGE 27 | REDIS_URL=redis://redis:6379 28 | 29 | # Port that the TellForm Node app will listen on 30 | PORT=5000 31 | 32 | # Domain that TellForm's admin panel will be hosted at 33 | BASE_URL=tellform.dev 34 | 35 | # Port that SocketIO server (for analytics) will listen on 36 | SOCKET_PORT=20523 37 | 38 | #Choose what kind of TLS you want 39 | TLS_FLAVOR=cert 40 | 41 | ################################### 42 | # Optional features 43 | ################################### 44 | 45 | # Set this to enable coveralls.io support 46 | COVERALLS_REPO_TOKEN=NC5TbhEeeJXqos552EHyRORvuVtTChTWq 47 | 48 | # Disable signups for your TellForm instance 49 | SIGNUP_DISABLED=FALSE 50 | 51 | # Disable per-user custom subdomains 52 | SUBDOMAINS_DISABLED=FALSE 53 | 54 | # Url that subdomains will be hosted at (has to have domain name as ADMIN_URL) 55 | # Only used when SUBDOMAINS_DISABLED=FALSE 56 | SUBDOMAIN_URL=*.tellform.dev 57 | 58 | # Enable running TellForm in pm2's 'cluster' mode 59 | ENABLE_CLUSTER_MODE=FALSE 60 | ################################### 61 | # Mail settings 62 | ################################### 63 | 64 | # Set this to set the username credential of your SMTP service 65 | MAILER_EMAIL_ID= 66 | 67 | # Set this to set the password credential of your SMTP service 68 | MAILER_PASSWORD= 69 | 70 | # Set this to set the email address that all email should be sent from for signup/verification emails 71 | MAILER_FROM= 72 | 73 | # Set this to any services from https://nodemailer.com/smtp/well-known/ to use a 'well-known' email provider 74 | MAILER_SERVICE_PROVIDER= 75 | 76 | # Set these if you are not using a 'MAILER_SERVICE_PROVIDER' and want to specify your SMTP server's address and port 77 | MAILER_SMTP_HOST= 78 | MAILER_SMTP_PORT= 79 | 80 | # Set this if you are using a custom SMTP server that supports SSL 81 | MAILER_SMTP_SECURE 82 | 83 | ################################### 84 | # Automatic Admin Creation Settings 85 | ################################### 86 | 87 | # Set this to "TRUE" if you wish to automatically create an admin user on startup 88 | CREATE_ADMIN=FALSE 89 | 90 | # Set this to set the email used by your default admin account 91 | ADMIN_EMAIL=admin@admin.com 92 | 93 | # Set this to set the username of your default admin acconut 94 | ADMIN_USERNAME=root 95 | 96 | # Set this to set the password of your default admin account 97 | ADMIN_PASSWORD=root 98 | 99 | ################################### 100 | # Advanced settings 101 | ################################### 102 | 103 | # Set this to server your websockets server on a seperate URL 104 | SOCKETS_URL= 105 | 106 | # Set this to change the port that TellForm will listen on 107 | PORT=5000 108 | 109 | # Set this to your Google Analytics ID to enable tracking with GA 110 | GOOGLE_ANALYTICS_ID= 111 | 112 | # Set this to your Sentry.io DSN code to enable front-end JS error tracking with Sentry.io 113 | RAVEN_DSN 114 | 115 | # Set this to set the 'name' meta property in the HTML 116 | APP_NAME= 117 | 118 | # Set this to set the 'keywords' meta property in the HTML 119 | APP_KEYWORDS= 120 | 121 | # Set this to set the 'description' meta property in the HTML head 122 | APP_DESC= 123 | -------------------------------------------------------------------------------- /.git.bfg-report/2017-11-13/14-44-35/protected-dirt/d2d906a9-HEAD.csv: -------------------------------------------------------------------------------- 1 | 647b6b87711d6c804fb73763f618ef2ae6ef6117,DELETE,regular-file,.env,3682, -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .DS_Store 3 | .git.bfg-report 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tellform"] 2 | path = tellform 3 | url = git@github.com:tellform/tellform 4 | branch = docker 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 TellForm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker Installation 2 | 3 | Before starting, ensure you have the latest versions of git, docker and docker-compose installed on your machine. 4 | 5 | ## Step 1: Clone the repo 6 | 7 | ``` 8 | $ git clone https://github.com/tellform/docker_files.git 9 | ``` 10 | 11 | ### Step 2: Setup TellForm Configuration 12 | 13 | Create your `.env` file by copying the `.env.dist` file included in the repo and changing it to suit your deployment. 14 | 15 | **Important**: You need to fill out all of the ENV variables in the "Mail Settings" section or your TellForm instance won't work. 16 | 17 | ### Step 3: Start your TellForm instance 18 | 19 | ```docker-compose up -d``` 20 | 21 | TellForm is now accessible on https://localhost 22 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | redis: 4 | restart: always 5 | image: redis 6 | volumes: 7 | - "${PWD}/.env:/opt/tellform/.env" 8 | mongo: 9 | restart: always 10 | image: mongo 11 | volumes: 12 | - "$ROOT/mongo:/data" 13 | tellform: 14 | image: tellform/app:stable 15 | env_file: 16 | - .env 17 | volumes: 18 | - "${PWD}/.env:/opt/tellform/.env" 19 | links: 20 | - mongo 21 | - redis 22 | depends_on: 23 | - mongo 24 | - redis 25 | web: 26 | image: tellform/nginx:stable 27 | restart: always 28 | ports: 29 | - "80:80" 30 | - "443:443" 31 | - "20523:20523" 32 | env_file: 33 | - .env 34 | volumes: 35 | - "$ROOT/certs:/certs" 36 | -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:edge 2 | RUN apk add --no-cache nginx certbot openssl python py-jinja2 3 | 4 | COPY conf /conf 5 | COPY *.py / 6 | 7 | RUN chmod +x /start.py 8 | RUN chmod +x /letsencrypt.py 9 | RUN chmod +x /config.py 10 | 11 | CMD /start.py 12 | -------------------------------------------------------------------------------- /nginx/README.md: -------------------------------------------------------------------------------- 1 | Mailu NGINX container 2 | ===================== 3 | 4 | NGINX is a popular and highly efficient webserver and reverse proxy server 5 | commonly used to power high performance websites. In the Mailu stack it is 6 | used as the HTTP frontend tunneling requests to the public web services 7 | provided by other containers. 8 | 9 | Resources 10 | --------- 11 | 12 | * [Report issues](https://github.com/Mailu/Mailu/issues) and 13 | [send Pull Requests](https://github.com/Mailu/Mailu/pulls) 14 | in the [main Mailu repository](https://github.com/Mailu/Mailu) -------------------------------------------------------------------------------- /nginx/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | # Basic configuration 2 | user nginx; 3 | worker_processes 1; 4 | error_log /dev/stderr info; 5 | pid /var/run/nginx.pid; 6 | 7 | events { 8 | worker_connections 1024; 9 | } 10 | 11 | http { 12 | # Standard HTTP configuration with slight hardening 13 | include /etc/nginx/mime.types; 14 | default_type application/octet-stream; 15 | access_log /dev/stdout; 16 | sendfile on; 17 | keepalive_timeout 65; 18 | server_tokens off; 19 | 20 | #Websockets Server 21 | server { 22 | 23 | {% if NODE_ENV == "development" %} 24 | listen {{SOCKET_PORT}}; 25 | {% else %} 26 | listen 80; 27 | listen [::]:80; 28 | server_name {{ SOCKETS_URL }}; 29 | 30 | # Only enable HTTPS if TLS is enabled with no error 31 | {% if TLS and not TLS_ERROR %} 32 | listen 443 ssl; 33 | listen [::]:443 ssl; 34 | 35 | include /etc/nginx/tls.conf; 36 | add_header Strict-Transport-Security max-age=15768000; 37 | 38 | if ($scheme = http) { 39 | return 301 https://$host$request_uri; 40 | } 41 | {% endif %} 42 | 43 | {% endif %} 44 | 45 | location / { 46 | proxy_pass http://tellform:20523; 47 | proxy_read_timeout 90; 48 | 49 | proxy_set_header Host $host; 50 | proxy_set_header X-Real-IP $remote_addr; 51 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 52 | proxy_set_header X-Forwarded-Proto $scheme; 53 | 54 | # WebSocket support 55 | proxy_http_version 1.1; 56 | proxy_set_header Upgrade $http_upgrade; 57 | proxy_set_header Connection "upgrade"; 58 | 59 | {% if TLS and not TLS_ERROR %} 60 | proxy_set_header X-Forwarded-Proto https; 61 | {% endif %} 62 | } 63 | 64 | {% if TLS_FLAVOR == 'letsencrypt' %} 65 | location ^~ /.well-known/acme-challenge/ { 66 | proxy_pass http://127.0.0.1:8008; 67 | } 68 | {% endif %} 69 | } 70 | 71 | server { 72 | #Add server_name for per-user subdomains 73 | {% if SUBDOMAINS_DISABLED == "FALSE" %} 74 | server_name {{BASE_URL}} {{SUBDOMAIN_URL}}; 75 | {% else %} 76 | server_name {{BASE_URL}}; 77 | {% endif %} 78 | 79 | listen 80; 80 | listen [::]:80; 81 | 82 | # Only enable HTTPS if TLS is enabled with no error 83 | {% if TLS and not TLS_ERROR %} 84 | listen 443 ssl; 85 | listen [::]:443 ssl; 86 | 87 | include /etc/nginx/tls.conf; 88 | add_header Strict-Transport-Security max-age=15768000; 89 | 90 | if ($scheme = http) { 91 | return 301 https://$host$request_uri; 92 | } 93 | {% endif %} 94 | 95 | root /usr/share/nginx/html; 96 | index index.html index.htm; 97 | 98 | location / { 99 | proxy_pass http://tellform:5000; 100 | proxy_redirect off; 101 | proxy_set_header Host $host; 102 | proxy_set_header X-Real-IP $remote_addr; 103 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; 104 | 105 | {% if TLS and not TLS_ERROR %} 106 | proxy_set_header X-Forwarded-Proto https; 107 | {% endif %} 108 | } 109 | 110 | {% if TLS_FLAVOR == 'letsencrypt' %} 111 | location ^~ /.well-known/acme-challenge/ { 112 | proxy_pass http://127.0.0.1:8008; 113 | } 114 | {% endif %} 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /nginx/conf/tls.conf: -------------------------------------------------------------------------------- 1 | ssl_protocols TLSv1.1 TLSv1.2; 2 | ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384'; 3 | ssl_prefer_server_ciphers on; 4 | ssl_session_timeout 10m; 5 | ssl_certificate {{ TLS[0] }}; 6 | ssl_certificate_key {{ TLS[1] }}; 7 | ssl_dhparam /certs/dhparam.pem; -------------------------------------------------------------------------------- /nginx/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import jinja2 4 | import os 5 | 6 | convert = lambda src, dst, args: open(dst, "w").write(jinja2.Template(open(src).read()).render(**args)) 7 | 8 | args = os.environ.copy() 9 | 10 | # TLS configuration 11 | args["TLS"] = { 12 | "cert": ("/certs/cert.pem", "/certs/key.pem"), 13 | "letsencrypt": ("/certs/letsencrypt/live/mailu/fullchain.pem", 14 | "/certs/letsencrypt/live/mailu/privkey.pem"), 15 | "notls": None 16 | }[args["TLS_FLAVOR"]] 17 | 18 | if args["TLS"] and not all(os.path.exists(file_path) for file_path in args["TLS"]): 19 | print("Missing cert or key file, disabling TLS") 20 | args["TLS_ERROR"] = "yes" 21 | 22 | 23 | # Build final configuration paths 24 | convert("/conf/tls.conf", "/etc/nginx/tls.conf", args) 25 | convert("/conf/nginx.conf", "/etc/nginx/nginx.conf", args) 26 | os.system("nginx -s reload") -------------------------------------------------------------------------------- /nginx/letsencrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os 4 | import time 5 | import subprocess 6 | 7 | 8 | command = [ 9 | "certbot", 10 | "-n", "--agree-tos", # non-interactive 11 | "-d", os.environ["HOSTNAMES"], 12 | "-m", "{}@{}".format(os.environ["POSTMASTER"], os.environ["DOMAIN"]), 13 | "certonly", "--standalone", 14 | "--cert-name", "mailu", 15 | "--preferred-challenges", "http", "--http-01-port", "8008", 16 | "--keep-until-expiring", 17 | "--rsa-key-size", "4096", 18 | "--config-dir", "/certs/letsencrypt", 19 | "--post-hook", "/config.py" 20 | ] 21 | 22 | # Wait for nginx to start 23 | time.sleep(5) 24 | 25 | # Run certbot every hour 26 | while True: 27 | subprocess.call(command) 28 | time.sleep(3600) 29 | -------------------------------------------------------------------------------- /nginx/nginx.conf.fallback: -------------------------------------------------------------------------------- 1 | # Basic configuration 2 | user nginx; 3 | worker_processes 1; 4 | error_log /dev/stderr info; 5 | pid /var/run/nginx.pid; 6 | include /etc/nginx/modules/devel_kit.conf; 7 | events { 8 | worker_connections 1024; 9 | } 10 | 11 | http { 12 | # Standard HTTP configuration with slight hardening 13 | include /etc/nginx/mime.types; 14 | default_type application/octet-stream; 15 | access_log /dev/stdout; 16 | sendfile on; 17 | keepalive_timeout 65; 18 | server_tokens off; 19 | 20 | server { 21 | listen 80; 22 | listen 443 ssl; 23 | 24 | # TLS configuration hardened according to: 25 | # https://bettercrypto.org/static/applied-crypto-hardening.pdf 26 | ssl_protocols TLSv1.1 TLSv1.2; 27 | ssl_ciphers 'EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA'; 28 | ssl_prefer_server_ciphers on; 29 | ssl_session_timeout 5m; 30 | ssl_session_cache shared:SSL:50m; 31 | ssl_certificate /tmp/snakeoil.pem; 32 | ssl_certificate_key /tmp/snakeoil.pem; 33 | 34 | add_header Strict-Transport-Security max-age=15768000; 35 | 36 | if ($scheme = http) { 37 | return 301 https://$host$request_uri; 38 | } 39 | 40 | root /usr/share/nginx/html; 41 | index index.html index.htm; 42 | 43 | location ~ /.well-known { 44 | allow all; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /nginx/start.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os 4 | import subprocess 5 | 6 | #Set default port 7 | if not os.environ["PORT"]: 8 | os.environ["PORT"] = "5000" 9 | 10 | #Set default sockets port 11 | if not os.environ["SOCKET_PORT"]: 12 | os.environ["SOCKET_PORT"] = "20523" 13 | 14 | # Actual startup script 15 | if not os.path.exists("/certs/dhparam.pem") and os.environ["TLS_FLAVOR"] != "notls": 16 | os.system("openssl dhparam -out /certs/dhparam.pem 2048") 17 | 18 | if os.environ["TLS_FLAVOR"] == "letsencrypt": 19 | subprocess.Popen(["/letsencrypt.py"]) 20 | elif os.environ["TLS_FLAVOR"] == "cert": 21 | if not os.path.exists("/certs/cert.pem"): 22 | os.system("openssl req -newkey rsa:2048 -x509 -keyout /certs/key.pem -out /certs/cert.pem -days 365 -nodes -subj '/C=NA/ST=None/L=None/O=None/CN=" + os.environ["BASE_URL"] + "'") 23 | 24 | subprocess.call(["/config.py"]) 25 | os.execv("/usr/sbin/nginx", ["nginx", "-g", "daemon off;"]) -------------------------------------------------------------------------------- /nginx/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z $ENABLE_CERTBOT ] || [ -f /certs/cert.pem ] 4 | then 5 | cp /etc/nginx/nginx.conf.default /etc/nginx/nginx.conf 6 | else 7 | openssl req -newkey rsa:2048 -x509 -keyout /certs/key.pem -out /certs/cert.pem -days 365 -nodes -subj "/C=NA/ST=None/L=None/O=None/CN=$DOMAIN" 8 | cp /etc/nginx/nginx.conf.fallback /etc/nginx/nginx.conf 9 | fi 10 | 11 | nginx -g 'daemon off;' 12 | --------------------------------------------------------------------------------