[TOOLS][DOCKER] Rewrite the configuration script to use whiptail/dialog, and refactor

This commit is contained in:
Hugo Sales 2021-03-20 23:09:50 +00:00
parent 8a48236d2d
commit 0e9737ee39
No known key found for this signature in database
GPG Key ID: 7D0C7EAFC9D835A0
18 changed files with 594 additions and 525 deletions

4
.gitignore vendored
View File

@ -29,8 +29,10 @@
DOCUMENTATION/database/*
!DOCUMENTATION/database/database.pdf
docker/certbot
docker/certbot/*
!docker/certbot/docker-compose.fragment.sh
docker/*/*.env
docker/mail/config/*
docker-compose.yaml
composer.local.json

View File

@ -1,37 +0,0 @@
#!/bin/sh
printf "Domain root: "
read -r domain_root
printf "Subdomain (can be empty): "
read -r sub_domain
printf "Use certificate signed by Let's Encrypt (Y/n): "
read -r signed
[ "${signed}" = "${signed#[Yy]}" ]
signed=$?
if [ $signed -ne 0 ]; then
printf "Email: "
read -r email
fi
if [ -z "$sub_domain" ]
then
domain="${domain_root}"
else
domain="${sub_domain}.${domain_root}"
fi
mkdir -p ./docker/bootstrap
cat > ./docker/bootstrap/bootstrap.env <<EOF
#!/bin/sh
email=${email}
domain=${domain}
domain_root=${domain_root}
signed=${signed}
EOF
chmod +x ./docker/bootstrap/bootstrap.env
docker-compose -f docker/bootstrap/bootstrap.yaml up

727
bin/configure vendored
View File

@ -1,389 +1,414 @@
#!/bin/sh
ROOT="$(git rev-parse --show-toplevel)"
HEIGHT=13
WIDTH=51
check_retval(){
case $1 in
1|255)
echo "Stopped"
exit;;
esac
}
check_input(){
if [ "$1" = "" ]
then
echo "Can't be empty"
exit
# ------------ Find the root folder where social is installed --------------
INSTALL_DIR="${PWD}"
while true; do
if [ ! -f "${INSTALL_DIR}/social.yaml" ]; then
INSTALL_DIR="$(dirname "${INSTALL_DIR}")"
elif [ "${INSTALL_DIR}" = '/' ]; then
echo "The current folder and it's parents don't seem to contain a valid GNU social installation, exiting"
exit 1
else
break
fi
}
exec 3>&1
domain_root=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "Domain root:" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $domain_root
exec 3>&1
sub_domain=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "Subdomain (can be empty):" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
exec 3>&1
signed=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--menu "Use certificate signed by Let's Encrypt?" $HEIGHT $WIDTH 2 \
"Y" "" \
"n" "" \
2>&1 1>&3)
check_retval $?
exec 3>&-
[ "${signed}" = "${signed#[Yy]}" ]
signed=$?
if [ $signed -ne 0 ]; then
exec 3>&1
email=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "Email:" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $email
fi
if [ -z "$sub_domain" ]
then
domain="${domain_root}"
else
domain="${sub_domain}.${domain_root}"
fi
mkdir -p $ROOT/docker/bootstrap
cat > $ROOT/docker/bootstrap/bootstrap.env <<EOF
#!/bin/sh
email=${email}
domain=${domain}
domain_root=${domain_root}
signed=${signed}
EOF
chmod +x ./docker/bootstrap/bootstrap.env
docker-compose -f docker/bootstrap/bootstrap.yaml up
git_dir=$PWD
while [ ! -d .git ]; do
git_dir=$(dirname "${git_dir}")
done
cd "${INSTALL_DIR}" || exit 1
# --------------------------------------------------------------------------
cd "${git_dir}" || exit
if [ ! -f ./docker/bootstrap/bootstrap.env ]; then
printf "bootstrap.env missing! Please run the bootstrap_certificates script.\n"
# ------------ Check whether the system has whiptail or dialog -------------
if command -v whiptail > /dev/null 2>&1; then
WHIPTAIL=whiptail
elif command -v dialog > /dev/null 2>&1; then
WHIPTAIL=dialog
else
echo "whiptail/dialog are not available, can't proceed"
exit 1
fi
. ./docker/bootstrap/bootstrap.env
# whiptail/dialog exits with 1 when cancelling through the UI, or 255 on ^C
validate_exit () {
case $1 in
1|255) printf "Canceling...\n" && exit 2 ;;
esac
}
# --------------------------------------------------------------------------
exec 3>&1
dbms=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--menu "Select DBMS:" $HEIGHT $WIDTH 2 \
"postgres" "" \
"mariadb" "" \
2>&1 1>&3)
check_retval $?
exec 3>&-
exec 3>&1
db=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "GNU social database name:" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
# TODO Add suport for other webservers
# ------------ Pick which services to configure through docker-compose and which to configure externally --------------
SERVICES=$(${WHIPTAIL} --title 'GNU social' --clear --backtitle 'GNU social' \
--menu "\nWelcome to the GNU social configurator. This program will help configure your GNU social node.\n\n\
Choose whether you prefer social to handle all the services it needs though docker,\nor if you'd rather use and configure your own:" 0 0 0 \
docker 'Docker service configuration' \
mixed 'Mixed docker/external service configuration' \
external 'External service configuration' \
3>&1 1>&2 2>&3)
validate_exit $?
case ${SERVICES} in
'docker') DOCKER='"nginx" "certbot" "php" "db" "redis" "mail"' ;;
'mixed')
DOCKER=$(${WHIPTAIL} --title 'GNU social Docker services' --clear --backtitle 'GNU social' \
--checklist "\nPick which of the following services you'd like to add to docker-compose.\n* indicates a service that has extra configuration" 0 0 0 \
nginx 'Configure NGINX' on \
certbot "Configure CertBot (automatic certificate renewing)" on \
php 'Configure PHP' on \
db 'Configure a DBMS*' on \
redis 'Configure Redis (optional, recommended)' on \
mail 'Confugure a mail server*' on \
3>&1 1>&2 2>&3)
validate_exit $?
;;
'external') DOCKER='' ;;
esac
# --------------------------------------------------------------------------
if [ "${dbms}" = 'mariadb' ]
then
exec 3>&1
user=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "Database user:" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $user
# ------------ If the user requested the use of docker services, ensure we have `docker` and `docker-compose` --------------
case ${SERVICES} in
'mixed'|'docker')
if ! (command -v docker > /dev/null 2>&1 && command -v docker-compose > /dev/null 2>&1); then
echo "docker/docker-compose are not available, can't proceed"
exit 1
fi
;;
esac
# --------------------------------------------------------------------------
# ------------ Regarless of whether using a docker container for the DBMS or not, we need to know which we're using, and it's settings --------------
DBMS=$(${WHIPTAIL} --title 'GNU social DBMS' --clear --backtitle 'GNU social' \
--radiolist "\nPick which DBMS you'd like to use" 0 0 0 \
postgres 'Use PostgreSQL' on \
mariadb 'Use MariaDB' off \
3>&1 1>&2 2>&3)
validate_exit $?
while true; do
DB_NAME=$(${WHIPTAIL} --title 'GNU social DB name' --clear --backtitle 'GNU social' \
--inputbox "\nEnter a name for the database to be used by social" 0 0 "social" \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${DB_NAME}" ]; then break; fi
done
if [ "${DBMS}" = 'postgres' ]; then DB_USER="postgres"; else DB_USER="social"; fi
while true; do
DB_USER=$(${WHIPTAIL} --title 'GNU social DB user' --clear --backtitle 'GNU social' \
--inputbox "\nEnter a user name for social to connect to the database under" 0 0 "${DB_USER}" \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${DB_USER}" ]; then break; fi
done
while true; do
DB_PASSWORD=$(${WHIPTAIL} --title 'GNU social DB password' --clear --backtitle 'GNU social' \
--passwordbox "\nEnter a password for social to connect to the database with" 0 0 \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${DB_PASSWORD}" ]; then break; fi
done
if [ "${DBMS}" = 'postgres' ]; then DB_DSN="postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}";
else DB_DSN="mysql://${DB_USER}:${DB_PASSWORD}@db:3306/${DB_NAME}"; fi
if echo "${DOCKER}" | grep -Fvq '"db"'; then
while true; do
DB_DSN=$(${WHIPTAIL} --title 'GNU social DB DSN' --clear --backtitle 'GNU social' \
--inputbox "\nEnter the DSN/URL for social to connect to the database with" 0 0 \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${DB_DSN}" ]; then break; fi
done
fi
if [ "${DBMS}" != 'postgres' ] && echo "${DOCKER}" | grep -Fq '"db"'; then
while true; do
DB_ROOT_PASSWORD=$(${WHIPTAIL} --title 'GNU social DB root user password' --clear --backtitle 'GNU social' \
--passwordbox "\nEnter a password for the database root user" 0 0 \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${DB_ROOT_PASSWORD}" ]; then break; fi
done
fi
# --------------------------------------------------------------------------
exec 3>&1
password=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "Database password:" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $password
exec 3>&1
sitename=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "Sitename:" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $sitename
exec 3>&1
admin_nick=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "Admin nickname:" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $admin_nick
exec 3>&1
admin_password=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "Admin password:" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $admin_password
exec 3>&1
profile=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--menu "Site profile:" $HEIGHT $WIDTH 4 \
"public" "" \
"private" "" \
"community" "" \
"single_user" "" \
2>&1 1>&3)
check_retval $?
exec 3>&-
exec 3>&1
mailer_dsn=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "Mailer dsn:" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $mailer_dsn
mkdir -p $ROOT/docker/db
if [ "${dbms}" = 'mariadb' ]; then
exec 3>&1
db_root_password=$(dialog \
--title "Configure" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "DB root password" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $db_root_password
cat > $ROOT/docker/db/db.env <<EOF
DBMS=${dbms}
MYSQL_ROOT_PASSWORD=${db_root_password}
EOF
database_url="DATABASE_URL=mysql://${user}:${password}@db:3306/${db}"
# ------------------------ Network configuration ----------------------------
while true; do
DOMAIN_ROOT=$(${WHIPTAIL} --title 'GNU social domain root' --clear --backtitle 'GNU social' \
--inputbox "\nEnter the root domain from where social will be served" 0 0 \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${DOMAIN_ROOT}" ]; then break; fi
done
# Subdomain is optional
SUBDOMAIN=$(${WHIPTAIL} --title 'GNU social subdomain' --clear --backtitle 'GNU social' \
--inputbox "\nEnter the subdomain from where social will be served, if any" 0 0 \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -z "${SUBDOMAIN}" ]; then
DOMAIN="${DOMAIN_ROOT}"
else
cat > $ROOT/docker/db/db.env <<EOF
DBMS=${dbms}
POSTGRES_USER=postgres
POSTGRES_PASSWORD=${password}
EOF
user='postgres'
database_url="DATABASE_URL=postgresql://${user}:${password}@db:5432/${db}"
DOMAIN="${SUBDOMAIN}.${DOMAIN_ROOT}"
fi
echo "${database_url}" >> .env.local
${WHIPTAIL} --title "Use Let's Encrypt certificate?" --clear --backtitle 'GNU social' \
--yesno "\nDo you want to use a certificate signed by Let's Encrypt? A self signed certificate will be created, \
as one is required, but you may provide your own" 0 0 \
3>&1 1>&2 2>&3
LE_CERT=$((1-$?)) # Invert output
mkdir -p $ROOT/docker/social
if [ $LE_CERT -ne 0 ]; then
while true; do
EMAIL=$(${WHIPTAIL} --title 'GNU social admin email' --clear --backtitle 'GNU social' \
--inputbox "\nEnter the email to register the admin user under" 0 0 \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${EMAIL}" ]; then break; fi
done
fi
cat > $ROOT/docker/social/social.env <<EOF
SOCIAL_DBMS="${dbms}"
SOCIAL_DB="${db}"
SOCIAL_USER="${user}"
SOCIAL_PASSWORD="${password}"
SOCIAL_DOMAIN="${domain}"
SOCIAL_SITENAME="${sitename}"
SOCIAL_ADMIN_NICK="${admin_nick}"
SOCIAL_ADMIN_PASSWORD="${admin_password}"
SOCIAL_ADMIN_EMAIL="${email}"
SOCIAL_SITE_PROFILE="${profile}"
MAILER_DSN="${mailer_dsn}"
while true; do
NODE_NAME=$(${WHIPTAIL} --title 'GNU social node name' --clear --backtitle 'GNU social' \
--inputbox "\nEnter the name for this GNU social node" 0 0 \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${NODE_NAME}" ]; then break; fi
done
while true; do
NGINX_HTTP_PORT=$(${WHIPTAIL} --title 'GNU social HTTP port' --clear --backtitle 'GNU social' \
--inputbox "\nWhich port should NGINX use for HTTP traffic ('host:port' is also valid)" 0 0 "80" \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${NGINX_HTTP_PORT}" ]; then break; fi
done
while true; do
NGINX_HTTPS_PORT=$(${WHIPTAIL} --title 'GNU social HTTPS port' --clear --backtitle 'GNU social' \
--inputbox "\nWhich port should NGINX use for HTTPS traffic ('host:port' is also valid)" 0 0 "443" \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${NGINX_HTTPS_PORT}" ]; then break; fi
done
PHP_PORT=9000
if echo "${DOCKER}" | grep -Fvq '"php"'; then
while true; do
PHP_PORT=$(${WHIPTAIL} --title 'GNU social PHP service port' --clear --backtitle 'GNU social' \
--inputbox "\nWhich port should be used for PHP" 0 0 "9000" \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${PHP_PORT}" ]; then break; fi
done
fi
# --------------------------------------------------------------------------
PROFILE=$(${WHIPTAIL} --title 'GNU social site profile' --clear --backtitle 'GNU social' \
--menu "\nPick one of the following node visibility presets:" 0 0 0 \
public 'Make this node publicly accessible, with open registration' \
community 'Make this node publicly accessible, but with invite-only registration' \
isolated 'Make this node publicly accessible, with open registration but do not federate' \
private 'Make this node publicly accessible, but with invite-only registration, only registered users can see timelines' \
single_user 'Like public, but only allows registering one user' \
3>&1 1>&2 2>&3)
validate_exit $?
# ------------ Mail server --------------
if echo "${DOCKER}" | grep -Fq '"mail"'; then
while true; do
MAILER_DSN=$(${WHIPTAIL} --title 'GNU social mail server DSN' --clear --backtitle 'GNU social' \
--inputbox "\nEnter a DSN/URL social will use to connect to the mail server" 0 0 'sendmail://localhost' \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${MAILER_DSN}" ]; then break; fi
done
fi
if echo "${DOCKER}" | grep -Fvq '"mail"'; then
while true; do
MAIL_DOMAIN_ROOT=$(${WHIPTAIL} --title 'GNU social mail server domain' --clear --backtitle 'GNU social' \
--inputbox "\nEnter the root domain social will use to serve mail" 0 0 "${DOMAIN_ROOT}" \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${MAIL_DOMAIN_ROOT}" ]; then break; fi
done
MAIL_SUBDOMAIN=$(${WHIPTAIL} --title 'GNU social mail server subdomain' --clear --backtitle 'GNU social' \
--inputbox "\nEnter a subdomain social will send email from (optional, can be empty)" 0 0 \
3>&1 1>&2 2>&3)
validate_exit $?
while true; do
MAIL_SENDER_USER=$(${WHIPTAIL} --title 'GNU social mail sender user' --clear --backtitle 'GNU social' \
--inputbox "\nEnter the user emails should be sent from" 0 0 \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${MAIL_SENDER_USER}" ]; then break; fi
done
while true; do
MAIL_SENDER_NAME=$(${WHIPTAIL} --title 'GNU social mail sender name' --clear --backtitle 'GNU social' \
--inputbox "\nEnter the name emails should be sent from (name without @domain)" 0 0 \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${MAIL_SENDER_NAME}" ]; then break; fi
done
while true; do
MAIL_PASSWORD=$(${WHIPTAIL} --title 'GNU social mail password' --clear --backtitle 'GNU social' \
--passwordbox "\nEnter a password for the user in the mail server" 0 0 \
3>&1 1>&2 2>&3)
validate_exit $?
if [ -n "${MAIL_PASSWORD}" ]; then break; fi
done
fi
# --------------------------------------------------------------------------
# --------------- Ensure we have the needed certificates -------------------
mkdir -p "${INSTALL_DIR}/docker/bootstrap"
cat > "${INSTALL_DIR}/docker/bootstrap/bootstrap.env" <<EOF
#!/bin/sh
DOMAIN="${DOMAIN}"
DOMAIN_ROOT="${DOMAIN_ROOT}"
SIGNED=${LE_CERT}
EOF
[ -n "${EMAIL}" ] && echo EMAIL="${EMAIL}" >> "${INSTALL_DIR}/docker/bootstrap/bootstrap.env"
chmod +x ./docker/bootstrap/bootstrap.env
docker-compose -f docker/bootstrap/bootstrap.yaml up
validate_exit $?
# --------------------------------------------------------------------------
# ------------ Configure parameters for the creation of docker containers --------------
mkdir -p "${INSTALL_DIR}/docker/db"
if [ "${DBMS}" = 'postgres' ]; then
cat > "${INSTALL_DIR}/docker/db/db.env" <<EOF
DBMS=${DBMS}
POSTGRES_USER=postgres
POSTGRES_PASSWORD=${DB_PASSWORD}
EOF
else
cat > "${INSTALL_DIR}/docker/db/db.env" <<EOF
DBMS="${DBMS}"
MYSQL_ROOT_PASSWORD="${DB_ROOT_PASSWORD}"
MYSQL_DATABASE="${DB_NAME}"
MYSQL_USER="${DB_USER}"
MYSQL_PASSWORD="${DB_PASSWORD}"
EOF
fi
touch .env.local
sed -ri 's/DATABASE_URL=.*//' .env.local
echo "DATABASE_URL=${DB_DSN}" >> .env.local
sed -ri 's/MAILER_DSN=.*//' .env.local
echo "MAILER_DSN=${MAILER_DSN}" >> .env.local
mkdir -p "${INSTALL_DIR}/docker/social"
cat > "${INSTALL_DIR}/docker/social/social.env" <<EOF
SOCIAL_DBMS="${DBMS}"
SOCIAL_DB="${DB_NAME}"
SOCIAL_USER="${DB_USER}"
SOCIAL_PASSWORD="${DB_PASSWORD}"
SOCIAL_DOMAIN="${DOMAIN}"
SOCIAL_SITENAME="${SITENAME}"
SOCIAL_ADMIN_EMAIL="${EMAIL}"
SOCIAL_SITE_PROFILE="${PROFILE}"
MAILER_DSN="${MAILER_DSN}"
EOF
# --------------------------------------------------------------------------
# TODO create admin user
#SOCIAL_ADMIN_NICK="${ADMIN_NICK}"
#SOCIAL_ADMIN_PASSWORD="${ADMIN_PASSWORD}"
# --------------- Write mail configuration, and setup ----------------------
mkdir -p "${INSTALL_DIR}/docker/mail"
if [ -z "${MAIL_SUBDOMAIN}" ]; then
MAIL_DOMAIN="${MAIL_DOMAIN_ROOT}"
else
MAIL_DOMAIN="${MAIL_SUBDOMAIN}.${MAIL_DOMAIN_ROOT}"
fi
cat > "${INSTALL_DIR}/docker/mail/mail.env" <<EOF
MAIL_DOMAIN="${MAIL_DOMAIN}"
MAIL_USER="${MAIL_SENDER_USER}"
MAIL_NAME="${MAIL_SENDER_NAME}"
MAIL="${MAIL_SENDER_USER}@${MAIL_DOMAIN}"
SSL_CERT=/etc/letsencrypt/live/${MAIL_DOMAIN_ROOT}/fullchain.pem
SSL_KEY=/etc/letsencrypt/live/${MAIL_DOMAIN_ROOT}/privkey.pem
EOF
HASHED_PASSWORD="{SHA512-CRYPT}"$(echo "${MAIL_PASSWORD}" | openssl passwd -6 -in -)
exec 3>&1
docker_compose=$(dialog \
--title "Services" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--checklist "Services to include in docker-compose:" $HEIGHT $WIDTH 6 \
"nginx" "" on \
"certbot" "" on \
"php" "" on \
"db" "" on \
"redis" "" on \
"mail" "" on \
2>&1 1>&3)
check_retval $?
exec 3>&-
# Config postfix
sed -ri \
-e "s/^\s*myhostname\s*=.*/myhostname = ${MAILNAME}/" \
-e "s/^\s*mydomain\s*=.*/mydomain = ${DOMAINNAME}/" \
-e "s/^\s*smtpd_tls_cert_file\s*=.*/smtpd_tls_cert_file = ${SSL_CERT}/" \
-e "s/^\s*smtpd_tls_key_file\s*=.*/smtpd_tls_key_file = ${SSL_KEY}/" \
"${INSTALL_DIR}/docker/mail/config/postfix/main.cf"
echo "version: '3.3'" > docker-compose.yaml
echo "\nservices:" >> docker-compose.yaml
# Config dovecot
sed -ri \
-e "s/^\s*ssl_cert\s*=.*/ssl_cert = <${SSL_CERT}/" \
-e "s/^\s*ssl_key\s*=.*/ssl_key = <${SSL_KEY}/" \
-e "s/^\s*postmaster_address\s*=.*/postmaster_address = postmaster@${DOMAINNAME}/" \
"${INSTALL_DIR}/docker/mail/config/dovecot/dovecot.conf"
case $docker_compose in *"nginx"*)
$ROOT/docker/social/nginx
esac
# Config dkim
sed -i -e "s/^.*#HOSTNAME/${MAILNAME}#HOSTNAME/" "${INSTALL_DIR}/docker/mail/config/opendkim/TrustedHosts"
case $docker_compose in *"certbot"*)
$ROOT/docker/social/certbot
esac
# Prepare mail user
echo "${MAIL_DOMAIN_ROOT} #OK" > "${INSTALL_DIR}/docker/mail/config/domains"
echo "${MAIL_USER} ${MAIL_USER}" > "${INSTALL_DIR}/docker/mail/config/aliases"
echo "${MAIL_USER} ${MAIL_DOMAIN_ROOT}/${MAIL_USER}/" > "${INSTALL_DIR}/docker/mail/config/mailboxes"
echo "${MAIL_USER}:${HASHED_PASSWORD}" > "${INSTALL_DIR}/docker/mail/config/passwd"
# --------------------------------------------------------------------------
case $docker_compose in *"php"*)
$ROOT/docker/social/php
esac
case $docker_compose in *"db"*)
$ROOT/docker/social/db
esac
case $docker_compose in *"redis"*)
$ROOT/docker/social/redis
esac
# ------------------- Write docker-compose config file ---------------------
cat > "${INSTALL_DIR}/docker-compose.yaml" <<EOF
version: '3'
case $docker_compose in *"mail"*)
$ROOT/docker/social/mail
exec 3>&1
mail_domain_root=$(dialog \
--title "Configure Mail" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "E-mail domain root:" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $mail_domain_root
exec 3>&1
mail_subdomain=$(dialog \
--title "Configure Mail" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "E-mail subdomain (can be empty):" $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
exec 3>&1
mail_user=$(dialog \
--title "Configure Mail" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "E-mail user (name without @domain): " $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $mail_user
exec 3>&1
mail_pass=$(dialog \
--title "Configure Mail" \
--clear \
--ok-label "Ok" \
--cancel-label "Exit" \
--inputbox "E-mail user password: " $HEIGHT $WIDTH \
2>&1 1>&3)
check_retval $?
exec 3>&-
check_input $mail_pass
mkdir -p $ROOT/docker/mail
cat > $ROOT/docker/mail/mail.env <<EOF
MAIL_DOMAIN_ROOT="${mail_domain_root}"
MAIL_SUBDOMAIN="${mail_subdomain}"
MAIL_USER="${mail_user}"
MAIL_PASSWORD="${mail_pass}"
services:
EOF
$ROOT/docker/mail/setup.sh
esac
echo "volumes:\n database:" >> docker-compose.yaml
export DOCKER="${DOCKER}"
export NGINX_HTTP_PORT="${NGINX_HTTP_PORT}"
export NGINX_HTTPS_PORT="${NGINX_HTTPS_PORT}"
export PHP_PORT="${PHP_PORT}"
export DBMS="${DBMS}"
for SERV in ${DOCKER}; do
SERV=$(echo "${SERV}" | sed -r 's/"([^"]*)"/\1/')
sh "${INSTALL_DIR}/docker/${SERV}/docker-compose.fragment.sh" >> "${INSTALL_DIR}/docker-compose.yaml"
done
if echo "${DOCKER}" | grep -Fq '"db"'; then
cat >> "${INSTALL_DIR}/docker-compose.yaml" <<EOF
volumes:
database:
EOF
fi
# --------------------------------------------------------------------------
cd "${OLDPWD}" || exit 1

View File

@ -2,7 +2,7 @@
. bootstrap.env
sed -ri "s/%hostname%/${domain}/" /etc/nginx/conf.d/challenge.conf
sed -ri "s/%hostname%/${DOMAIN}/" /etc/nginx/conf.d/challenge.conf
nginx
@ -12,49 +12,45 @@ lets_path="/etc/letsencrypt"
echo "Starting bootstrap"
if [ ! -e "$lets_path/live//options-ssl-nginx.conf" ] || [ ! -e "$lets_path/live/ssl-dhparams.pem" ]
then
if [ ! -e "$lets_path/live//options-ssl-nginx.conf" ] || [ ! -e "$lets_path/live/ssl-dhparams.pem" ];then
echo "### Downloading recommended TLS parameters ..."
mkdir -p "${lets_path}/live/${domain_root}"
mkdir -p "${lets_path}/live/${DOMAIN}"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf >"$lets_path/options-ssl-nginx.conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem >"$lets_path/ssl-dhparams.pem"
if [ ${signed} -eq 0 ]
then
echo "### Creating self signed certificate for ${domain_root} ..."
if [ ${SIGNED} -eq 0 ]; then
echo "### Creating self signed certificate for ${DOMAIN} ..."
openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 365 \
-keyout "${lets_path}/live/${domain_root}/privkey.pem" \
-out "${lets_path}/live/${domain_root}/fullchain.pem" -subj "/CN=${domain_root}"
-keyout "${lets_path}/live/${DOMAIN}/privkey.pem" \
-out "${lets_path}/live/${DOMAIN}/fullchain.pem" -subj "/CN=${DOMAIN}"
else
echo "### Creating dummy certificate for ${domain_root} ..."
echo "### Creating dummy certificate for ${DOMAIN} ..."
openssl req -x509 -nodes -newkey rsa:1024 -days 1 \
-keyout "${lets_path}/live/${domain_root}/privkey.pem" \
-out "${lets_path}/live/${domain_root}/fullchain.pem" -subj '/CN=localhost'
-keyout "${lets_path}/live/${DOMAIN}/privkey.pem" \
-out "${lets_path}/live/${DOMAIN}/fullchain.pem" -subj '/CN=localhost'
nginx -s reload
rm -Rf "${lets_path}/live/${domain_root}"
rm -Rf "${lets_path}/archive/${domain_root}"
rm -Rf "${lets_path}/renewal/${domain_root}.conf"
rm -Rf "${lets_path}/live/${DOMAIN}"
rm -Rf "${lets_path}/archive/${DOMAIN}"
rm -Rf "${lets_path}/renewal/${DOMAIN}.conf"
echo "### Requesting Let's Encrypt certificate for ${domain_root} ..."
echo "### Requesting Let's Encrypt certificate for ${DOMAIN} ..."
# Format domain_args with the cartesian product of `domain_root` and `subdomains`
if [ "${domain_root}" = "${domain}" ]; then domain_arg="-d ${domain_root}"; else domain_arg="-d ${domain_root} -d ${domain}"; fi
# if [ "${DOMAIN_ROOT}" = "${DOMAIN}" ]; then domain_arg="-d ${DOMAIN_ROOT}"; else domain_arg="-d ${DOMAIN_ROOT} -d ${DOMAIN}"; fi
# ${domain_arg} \
# Ask Let's Encrypt to create certificates, if challenge passed
certbot certonly --webroot -w "${certbot_path}" \
--email "${email}" \
${domain_arg} \
--email "${EMAIL}" \
-d "${DOMAIN}" \
--non-interactive \
--rsa-key-size "${rsa_key_size}" \
--agree-tos \
--force-renewal
fi
else
echo "Certificate related files exists, exiting"
fi

View File

@ -0,0 +1,27 @@
#!/usr/bin/sh
cat <<EOF
certbot:
image: certbot/certbot
EOF
# If the user wants a nginx docker container
if echo "${DOCKER}" | grep -Fvq '"nginx"'; then
cat <<EOF
depends_on:
- nginx
EOF
fi
cat <<EOF
# Check for certificate renewal every 12h as
# recommended by Let's Encrypt
entrypoint: /bin/sh -c 'trap exit TERM;
while :; do
certbot renew > /dev/null;
sleep 12h & wait \$\${!};
done'
volumes:
- ./docker/certbot/www:/var/www/certbot
- ./docker/certbot/.files:/etc/letsencrypt
EOF

View File

@ -0,0 +1,31 @@
#!/usr/bin/sh
if [ "${DBMS}" = 'postgres' ]; then
cat <<EOF
db:
image: postgres:alpine
restart: always
tty: false
ports:
- 5432:5432
environment:
- PGDATA=/var/lib/postgres/data
env_file:
- ./docker/db/db.env
volumes:
- database:/var/lib/postgres/data
EOF
else
cat <<EOF
db:
image: mariadb
restart: always
tty: false
ports:
- 3306:3306
env_file:
- ./docker/db/db.env
EOF
fi

View File

@ -3,8 +3,7 @@ FROM debian:buster-slim
ENV DEBIAN_FRONTEND=noninteractive
# Install packages
RUN \
apt-get update \
RUN apt-get update \
&& apt-get upgrade -y \
&& apt-get install -y --no-install-recommends \
dovecot-core \
@ -22,8 +21,7 @@ RUN \
&& apt-get autoremove
# Setup folders and users
RUN \
groupadd -g 2222 vmail \
RUN groupadd -g 2222 vmail \
&& mkdir -p -m 751 "/var/mail/" \
&& mkdir -p -m 755 "/etc/mail/" \
&& mkdir -p "/var/opendkim/keys/" \
@ -37,19 +35,17 @@ RUN \
# Copy config files
COPY rootfs/ /
RUN \
chmod +x "/etc/service/postfix/run" \
RUN chmod +x "/etc/service/postfix/run" \
&& chmod +x "/etc/service/dovecot/run" \
&& chmod +x "/etc/service/opendkim/run" \
&& chmod +x "/etc/service/rsyslog/run" \
&& chmod +x "/usr/bin/start.sh"
# Prepare user
RUN \
mkdir -p "/var/mail/${DOMAINNAME}" \
RUN mkdir -p "/var/mail/${MAIL_DOMAIN}" \
&& mkdir -p "/var/mail/${DOMAINPART}/${USER%@*}" \
&& chown vmail:vmail "/var/mail/${DOMAINNAME}" \
&& chown vmail:vmail "/var/mail/${DOMAINPART}/${USER%@*}"
&& chown vmail:vmail "/var/mail/${MAIL_DOMAIN}" \
&& chown vmail:vmail "/var/mail/${MAIL_DOMAIN_ROOT}/${MAIL_USER%@*}"
# Expose ports
EXPOSE 25 110 143 587 993 995

View File

@ -0,0 +1,21 @@
#!/usr/bin/sh
cat <<EOF
mail:
build: docker/mail
env_file:
- ./docker/mail/mail.env
ports:
- 25:25
- 110:110
- 143:143
- 587:587
- 993:993
volumes:
- ./docker/mail/mail:/var/mail
- ./docker/mail/config:/etc/mail
# Certbot
- ./docker/certbot/www:/var/www/certbot
- ./docker/certbot/.files:/etc/letsencrypt
EOF

View File

@ -0,0 +1,52 @@
#!/usr/bin/sh
cat <<EOF
nginx:
image: nginx:alpine
EOF
# If the user wants a PHP docker container
if echo "${DOCKER}" | grep -Fq '"php"'; then
cat <<EOF
depends_on:
- php
EOF
fi
cat <<EOF
restart: always
tty: false
ports:
- "${NGINX_HTTP_PORT}:80"
- "${NGINX_HTTPS_PORT}:443"
volumes:
# Nginx
- ./docker/nginx/nginx.conf:/var/nginx/social.conf
- ./docker/nginx/domain.sh:/var/nginx/domain.sh
# Certbot
- ./docker/certbot/www:/var/www/certbot
- ./docker/certbot/.files:/etc/letsencrypt
# social
- ./public:/var/www/social/public
env_file:
- ./docker/bootstrap/bootstrap.env
- ./docker/db/db.env
EOF
# If the user wants a Certbot docker container
if echo "${DOCKER}" | grep -Fq '"certbot"'; then
cat <<EOF
command: /bin/sh -c '/var/nginx/domain.sh;
while :; do
sleep 6h & wait \$\${!};
nginx -s reload;
done &
nginx -g "daemon off;"'
EOF
else
cat <<EOF
command: 'nginx -g \"daemon off;\"'
EOF
fi

View File

@ -1,5 +1,6 @@
#!/bin/sh
# Can't do sed inplace, because the file would be busy
cat /var/nginx/social.conf | \
sed -r "s/%hostname%/$domain/g; s/%hostname_root%/$domain_root/g" > \
sed -r "s/%hostname%/${DOMAIN}/g;" > \
/etc/nginx/conf.d/social.conf

View File

@ -14,8 +14,8 @@ server {
listen [::]:443 ssl http2;
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/%hostname_root%/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/%hostname_root%/privkey.pem;
ssl_certificate /etc/letsencrypt/live/%hostname%/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/%hostname%/privkey.pem;
# Let's Encrypt best practices
include /etc/letsencrypt/options-ssl-nginx.conf;

View File

@ -0,0 +1,34 @@
#!/usr/bin/sh
cat <<EOF
php:
build: docker/php
EOF
# If the user wants a DB docker container
if echo "${DOCKER}" | grep -Fvq '"db"'; then
cat <<EOF
depends_on:
- db
EOF
fi
cat <<EOF
restart: always
tty: true
ports:
- ${PHP_PORT}:9000
volumes:
# Entrypoint
- ./docker/php/entrypoint.sh:/entrypoint.sh
- ./docker/db/wait_for_db.sh:/wait_for_db.sh
- ./docker/social/install.sh:/var/entrypoint.d/social_install.sh
# Main files
- .:/var/www/social
env_file:
- ./docker/social/social.env
- ./docker/db/db.env
command: /entrypoint.sh
EOF

View File

@ -0,0 +1,11 @@
#!/usr/bin/sh
cat <<EOF
redis:
image: redis:alpine
restart: always
tty: false
ports:
- 6379:6379
EOF

View File

@ -1,14 +0,0 @@
#!/bin/sh
echo " db:
image: postgres:alpine
restart: always
tty: false
ports:
- 5432:5432
environment:
- PGDATA=/var/lib/postgres/data
env_file:
- ./docker/db/db.env
volumes:
- database:/var/lib/postgres/data\n" >> docker-compose.yaml

View File

@ -1,18 +0,0 @@
#!/bin/sh
echo " mail:
build: docker/mail
env_file:
- ./docker/mail/mail.env
ports:
- 25:25
- 110:110
- 143:143
- 587:587
- 993:993
volumes:
- ./docker/mail/mail:/var/mail
- ./docker/mail/config:/etc/mail
# Certbot
- ./docker/certbot/www:/var/www/certbot
- ./docker/certbot/.files:/etc/letsencrypt\n" >> docker-compose.yaml

View File

@ -1,29 +0,0 @@
#!/bin/sh
echo " nginx:
image: nginx:alpine
depends_on:
- php
restart: always
tty: false
ports:
- 80:80
- 443:443
volumes:
# Nginx
- ./docker/nginx/nginx.conf:/var/nginx/social.conf
- ./docker/nginx/domain.sh:/var/nginx/domain.sh
# Certbot
- ./docker/certbot/www:/var/www/certbot
- ./docker/certbot/.files:/etc/letsencrypt
# Social
- ./public:/var/www/social/public
env_file:
- ./docker/bootstrap/bootstrap.env
- ./docker/db/db.env
command: /bin/sh -c '/var/nginx/domain.sh;
while :; do
sleep 6h & wait \$\${!};
nginx -s reload;
done &
nginx -g \"daemon off;\"'\n" >> docker-compose.yaml

View File

@ -1,21 +0,0 @@
#!/bin/sh
echo " php:
build: docker/php
depends_on:
- db
restart: always
tty: true
ports:
- 9000:9000
volumes:
# Entrypoint
- ./docker/php/entrypoint.sh:/entrypoint.sh
- ./docker/db/wait_for_db.sh:/wait_for_db.sh
- ./docker/social/install.sh:/var/entrypoint.d/social_install.sh
# Main files
- .:/var/www/social
env_file:
- ./docker/social/social.env
- ./docker/db/db.env
command: /entrypoint.sh\n" >> docker-compose.yaml

View File

@ -1,8 +0,0 @@
#!/bin/sh
echo " redis:
image: redis:alpine
restart: always
tty: false
ports:
- 6379:6379\n" >> docker-compose.yaml