[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/*
!DOCUMENTATION/database/database.pdf !DOCUMENTATION/database/database.pdf
docker/certbot docker/certbot/*
!docker/certbot/docker-compose.fragment.sh
docker/*/*.env docker/*/*.env
docker/mail/config/*
docker-compose.yaml docker-compose.yaml
composer.local.json 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 #!/bin/sh
ROOT="$(git rev-parse --show-toplevel)" # ------------ Find the root folder where social is installed --------------
HEIGHT=13 INSTALL_DIR="${PWD}"
WIDTH=51 while true; do
if [ ! -f "${INSTALL_DIR}/social.yaml" ]; then
check_retval(){ INSTALL_DIR="$(dirname "${INSTALL_DIR}")"
case $1 in elif [ "${INSTALL_DIR}" = '/' ]; then
1|255) echo "The current folder and it's parents don't seem to contain a valid GNU social installation, exiting"
echo "Stopped" exit 1
exit;; else
esac break
}
check_input(){
if [ "$1" = "" ]
then
echo "Can't be empty"
exit
fi 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 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 exit 1
fi 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 # TODO Add suport for other webservers
db=$(dialog \ # ------------ Pick which services to configure through docker-compose and which to configure externally --------------
--title "Configure" \ SERVICES=$(${WHIPTAIL} --title 'GNU social' --clear --backtitle 'GNU social' \
--clear \ --menu "\nWelcome to the GNU social configurator. This program will help configure your GNU social node.\n\n\
--ok-label "Ok" \ 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 \
--cancel-label "Exit" \ docker 'Docker service configuration' \
--inputbox "GNU social database name:" $HEIGHT $WIDTH \ mixed 'Mixed docker/external service configuration' \
2>&1 1>&3) external 'External service configuration' \
check_retval $? 3>&1 1>&2 2>&3)
exec 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 # ------------ If the user requested the use of docker services, ensure we have `docker` and `docker-compose` --------------
user=$(dialog \ case ${SERVICES} in
--title "Configure" \ 'mixed'|'docker')
--clear \ if ! (command -v docker > /dev/null 2>&1 && command -v docker-compose > /dev/null 2>&1); then
--ok-label "Ok" \ echo "docker/docker-compose are not available, can't proceed"
--cancel-label "Exit" \ exit 1
--inputbox "Database user:" $HEIGHT $WIDTH \ fi
2>&1 1>&3) ;;
check_retval $? esac
exec 3>&- # --------------------------------------------------------------------------
check_input $user
# ------------ 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 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 # ------------------------ Network configuration ----------------------------
admin_nick=$(dialog \ while true; do
--title "Configure" \ DOMAIN_ROOT=$(${WHIPTAIL} --title 'GNU social domain root' --clear --backtitle 'GNU social' \
--clear \ --inputbox "\nEnter the root domain from where social will be served" 0 0 \
--ok-label "Ok" \ 3>&1 1>&2 2>&3)
--cancel-label "Exit" \ validate_exit $?
--inputbox "Admin nickname:" $HEIGHT $WIDTH \ if [ -n "${DOMAIN_ROOT}" ]; then break; fi
2>&1 1>&3) done
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}"
# 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 else
cat > $ROOT/docker/db/db.env <<EOF DOMAIN="${SUBDOMAIN}.${DOMAIN_ROOT}"
DBMS=${dbms}
POSTGRES_USER=postgres
POSTGRES_PASSWORD=${password}
EOF
user='postgres'
database_url="DATABASE_URL=postgresql://${user}:${password}@db:5432/${db}"
fi 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 while true; do
SOCIAL_DBMS="${dbms}" NODE_NAME=$(${WHIPTAIL} --title 'GNU social node name' --clear --backtitle 'GNU social' \
SOCIAL_DB="${db}" --inputbox "\nEnter the name for this GNU social node" 0 0 \
SOCIAL_USER="${user}" 3>&1 1>&2 2>&3)
SOCIAL_PASSWORD="${password}" validate_exit $?
SOCIAL_DOMAIN="${domain}" if [ -n "${NODE_NAME}" ]; then break; fi
SOCIAL_SITENAME="${sitename}" done
SOCIAL_ADMIN_NICK="${admin_nick}"
SOCIAL_ADMIN_PASSWORD="${admin_password}" while true; do
SOCIAL_ADMIN_EMAIL="${email}" NGINX_HTTP_PORT=$(${WHIPTAIL} --title 'GNU social HTTP port' --clear --backtitle 'GNU social' \
SOCIAL_SITE_PROFILE="${profile}" --inputbox "\nWhich port should NGINX use for HTTP traffic ('host:port' is also valid)" 0 0 "80" \
MAILER_DSN="${mailer_dsn}" 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 EOF
HASHED_PASSWORD="{SHA512-CRYPT}"$(echo "${MAIL_PASSWORD}" | openssl passwd -6 -in -)
exec 3>&1 # Config postfix
docker_compose=$(dialog \ sed -ri \
--title "Services" \ -e "s/^\s*myhostname\s*=.*/myhostname = ${MAILNAME}/" \
--clear \ -e "s/^\s*mydomain\s*=.*/mydomain = ${DOMAINNAME}/" \
--ok-label "Ok" \ -e "s/^\s*smtpd_tls_cert_file\s*=.*/smtpd_tls_cert_file = ${SSL_CERT}/" \
--cancel-label "Exit" \ -e "s/^\s*smtpd_tls_key_file\s*=.*/smtpd_tls_key_file = ${SSL_KEY}/" \
--checklist "Services to include in docker-compose:" $HEIGHT $WIDTH 6 \ "${INSTALL_DIR}/docker/mail/config/postfix/main.cf"
"nginx" "" on \
"certbot" "" on \
"php" "" on \
"db" "" on \
"redis" "" on \
"mail" "" on \
2>&1 1>&3)
check_retval $?
exec 3>&-
echo "version: '3.3'" > docker-compose.yaml # Config dovecot
echo "\nservices:" >> docker-compose.yaml 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"*) # Config dkim
$ROOT/docker/social/nginx sed -i -e "s/^.*#HOSTNAME/${MAILNAME}#HOSTNAME/" "${INSTALL_DIR}/docker/mail/config/opendkim/TrustedHosts"
esac
case $docker_compose in *"certbot"*) # Prepare mail user
$ROOT/docker/social/certbot echo "${MAIL_DOMAIN_ROOT} #OK" > "${INSTALL_DIR}/docker/mail/config/domains"
esac 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"*) # ------------------- Write docker-compose config file ---------------------
$ROOT/docker/social/redis cat > "${INSTALL_DIR}/docker-compose.yaml" <<EOF
esac version: '3'
case $docker_compose in *"mail"*) services:
$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}"
EOF EOF
$ROOT/docker/mail/setup.sh export DOCKER="${DOCKER}"
export NGINX_HTTP_PORT="${NGINX_HTTP_PORT}"
esac export NGINX_HTTPS_PORT="${NGINX_HTTPS_PORT}"
export PHP_PORT="${PHP_PORT}"
echo "volumes:\n database:" >> docker-compose.yaml 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 . 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 nginx
@ -12,49 +12,45 @@ lets_path="/etc/letsencrypt"
echo "Starting bootstrap" echo "Starting bootstrap"
if [ ! -e "$lets_path/live//options-ssl-nginx.conf" ] || [ ! -e "$lets_path/live/ssl-dhparams.pem" ] if [ ! -e "$lets_path/live//options-ssl-nginx.conf" ] || [ ! -e "$lets_path/live/ssl-dhparams.pem" ];then
then
echo "### Downloading recommended TLS parameters ..." 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-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" curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem >"$lets_path/ssl-dhparams.pem"
if [ ${signed} -eq 0 ] if [ ${SIGNED} -eq 0 ]; then
then echo "### Creating self signed certificate for ${DOMAIN} ..."
echo "### Creating self signed certificate for ${domain_root} ..."
openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 365 \ openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 365 \
-keyout "${lets_path}/live/${domain_root}/privkey.pem" \ -keyout "${lets_path}/live/${DOMAIN}/privkey.pem" \
-out "${lets_path}/live/${domain_root}/fullchain.pem" -subj "/CN=${domain_root}" -out "${lets_path}/live/${DOMAIN}/fullchain.pem" -subj "/CN=${DOMAIN}"
else else
echo "### Creating dummy certificate for ${domain_root} ..." echo "### Creating dummy certificate for ${DOMAIN} ..."
openssl req -x509 -nodes -newkey rsa:1024 -days 1 \ openssl req -x509 -nodes -newkey rsa:1024 -days 1 \
-keyout "${lets_path}/live/${domain_root}/privkey.pem" \ -keyout "${lets_path}/live/${DOMAIN}/privkey.pem" \
-out "${lets_path}/live/${domain_root}/fullchain.pem" -subj '/CN=localhost' -out "${lets_path}/live/${DOMAIN}/fullchain.pem" -subj '/CN=localhost'
nginx -s reload nginx -s reload
rm -Rf "${lets_path}/live/${domain_root}" rm -Rf "${lets_path}/live/${DOMAIN}"
rm -Rf "${lets_path}/archive/${domain_root}" rm -Rf "${lets_path}/archive/${DOMAIN}"
rm -Rf "${lets_path}/renewal/${domain_root}.conf" 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` # 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 # Ask Let's Encrypt to create certificates, if challenge passed
certbot certonly --webroot -w "${certbot_path}" \ certbot certonly --webroot -w "${certbot_path}" \
--email "${email}" \ --email "${EMAIL}" \
${domain_arg} \ -d "${DOMAIN}" \
--non-interactive \ --non-interactive \
--rsa-key-size "${rsa_key_size}" \ --rsa-key-size "${rsa_key_size}" \
--agree-tos \ --agree-tos \
--force-renewal --force-renewal
fi fi
else else
echo "Certificate related files exists, exiting" echo "Certificate related files exists, exiting"
fi 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 ENV DEBIAN_FRONTEND=noninteractive
# Install packages # Install packages
RUN \ RUN apt-get update \
apt-get update \
&& apt-get upgrade -y \ && apt-get upgrade -y \
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
dovecot-core \ dovecot-core \
@ -22,8 +21,7 @@ RUN \
&& apt-get autoremove && apt-get autoremove
# Setup folders and users # Setup folders and users
RUN \ RUN groupadd -g 2222 vmail \
groupadd -g 2222 vmail \
&& mkdir -p -m 751 "/var/mail/" \ && mkdir -p -m 751 "/var/mail/" \
&& mkdir -p -m 755 "/etc/mail/" \ && mkdir -p -m 755 "/etc/mail/" \
&& mkdir -p "/var/opendkim/keys/" \ && mkdir -p "/var/opendkim/keys/" \
@ -37,19 +35,17 @@ RUN \
# Copy config files # Copy config files
COPY rootfs/ / COPY rootfs/ /
RUN \ RUN chmod +x "/etc/service/postfix/run" \
chmod +x "/etc/service/postfix/run" \
&& chmod +x "/etc/service/dovecot/run" \ && chmod +x "/etc/service/dovecot/run" \
&& chmod +x "/etc/service/opendkim/run" \ && chmod +x "/etc/service/opendkim/run" \
&& chmod +x "/etc/service/rsyslog/run" \ && chmod +x "/etc/service/rsyslog/run" \
&& chmod +x "/usr/bin/start.sh" && chmod +x "/usr/bin/start.sh"
# Prepare user # Prepare user
RUN \ RUN mkdir -p "/var/mail/${MAIL_DOMAIN}" \
mkdir -p "/var/mail/${DOMAINNAME}" \
&& mkdir -p "/var/mail/${DOMAINPART}/${USER%@*}" \ && mkdir -p "/var/mail/${DOMAINPART}/${USER%@*}" \
&& chown vmail:vmail "/var/mail/${DOMAINNAME}" \ && chown vmail:vmail "/var/mail/${MAIL_DOMAIN}" \
&& chown vmail:vmail "/var/mail/${DOMAINPART}/${USER%@*}" && chown vmail:vmail "/var/mail/${MAIL_DOMAIN_ROOT}/${MAIL_USER%@*}"
# Expose ports # Expose ports
EXPOSE 25 110 143 587 993 995 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 #!/bin/sh
# Can't do sed inplace, because the file would be busy
cat /var/nginx/social.conf | \ 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 /etc/nginx/conf.d/social.conf

View File

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