diff --git a/basic/srv/vm/mgr/__init__.py b/basic/srv/vm/mgr/__init__.py
index 925babb..d13278e 100644
--- a/basic/srv/vm/mgr/__init__.py
+++ b/basic/srv/vm/mgr/__init__.py
@@ -5,7 +5,6 @@ import os
import shutil
import subprocess
-from . import confupdater
from . import tools
from . import validator
@@ -27,7 +26,7 @@ NGINX_TEMPLATE = '''server {{
error_log /var/log/nginx/{app}.error.log;
location / {{
- proxy_pass http://{ip}:8080;
+ proxy_pass http://{app}:8080;
}}
error_page 502 /502.html;
@@ -212,37 +211,50 @@ class VMMgr:
subprocess.run(['/sbin/rc-update', 'del', app])
def clean_ephemeral(self):
- # Remove ephemeral layer data
+ # Extract the variables from values given via lxc.hook.pre-start or lxc.hook.post-stop hook
app = os.environ['LXC_NAME']
+ # Remove ephemeral layer data
tools.clean_ephemeral_layer(app)
def register_container(self):
- # Set IP of a container based on values given via lxc.hook.start-host hook
+ # Extract the variables from values given via lxc.hook.start-host hook
app = os.environ['LXC_NAME']
pid = os.environ['LXC_PID']
+ # Configure host and common params used in the app
+ self.configure_app(app)
+ # Lease the first unused IP to the container
ip = tools.get_unused_ip()
tools.update_hosts_lease(ip, app)
tools.set_container_ip(pid, ip)
def unregister_container(self):
- # Unset IP of a container based on values given via lxc.hook.post-stop hook
+ # Extract the variables from values given via lxc.hook.post-stop hook
app = os.environ['LXC_NAME']
+ # Release the container IP
tools.update_hosts_lease(None, app)
# Remove ephemeral layer data
tools.clean_ephemeral_layer(app)
- def register_proxy(self, app, reload_nginx=True):
- # Rebuild nginx configuration using IP of referenced app container and reload nginx
+ def configure_app(self, app):
+ script = os.path.join('/srv', app, 'update-conf.sh')
+ if os.path.exists(script):
+ setup_env = os.environ.copy()
+ setup_env['DOMAIN'] = self.domain
+ setup_env['PORT'] = self.port
+ setup_env['EMAIL'] = self.conf['common']['email']
+ setup_env['GMAPS_API_KEY'] = self.conf['common']['gmaps-api-key']
+ subprocess.run([script], env=setup_env, check=True)
+
+ def register_proxy(self, app):
+ # Setup proxy configuration and reload nginx
if not validator.is_valid_app(app, self.conf):
raise validator.InvalidValueException('app', app)
- ip = tools.get_container_ip(app)
with open(os.path.join(NGINX_DIR, '{}.conf'.format(app)), 'w') as f:
- f.write(NGINX_TEMPLATE.format(app=app, host=self.conf['apps'][app]['host'], ip=ip, domain=self.domain, port=self.port))
- if reload_nginx:
- tools.reload_nginx()
+ f.write(NGINX_TEMPLATE.format(app=app, host=self.conf['apps'][app]['host'], domain=self.domain, port=self.port))
+ tools.reload_nginx()
def unregister_proxy(self, app):
- # Remove nginx configuration to prevent proxy mismatch when the container IP is reassigned to another container
+ # Remove proxy configuration and reload nginx
if not validator.is_valid_app(app, self.conf):
raise validator.InvalidValueException('app', app)
os.unlink(os.path.join(NGINX_DIR, '{}.conf'.format(app)))
@@ -257,17 +269,17 @@ class VMMgr:
self.domain = self.conf['host']['domain'] = domain
self.port = self.conf['host']['port'] = port
self.save_conf()
+ # Restart all apps to trigger configuration refresh
+ for app in self.conf['apps']:
+ if tools.is_service_started(app):
+ tools.restart_service(app)
+ # Rebuild and restart nginx if it was requested. Web interface calls tools.restart_nginx() in WSGI close handler
self.rebuild_nginx(restart_nginx)
- self.update_apps_urls()
def rebuild_nginx(self, restart_nginx):
# Rebuild nginx config for the portal app
with open(os.path.join(NGINX_DIR, 'default.conf'), 'w') as f:
f.write(NGINX_DEFAULT_TEMPLATE.format(port=self.port))
- # Re-register nginx proxy for running apps
- for app in self.conf['apps']:
- if tools.is_service_started(app):
- self.register_proxy(app, False)
# Restart nginx to properly bind the new listen port
if restart_nginx:
tools.restart_nginx()
@@ -286,14 +298,6 @@ class VMMgr:
with open(ISSUE_FILE, 'w') as f:
f.write(ISSUE_TEMPLATE.format(url=tools.compile_url(domain, self.port)))
- def update_apps_urls(self):
- # Update configuration for respective applications
- confupdater.update_url(self.domain, self.port)
- # Restart currently running apps in order to update config and re-register nginx proxy
- for app in self.conf['apps']:
- if tools.is_service_started(app):
- tools.restart_service(app)
-
def update_common(self, email, gmaps_api_key):
# Update common configuration values
if email != None:
@@ -301,21 +305,21 @@ class VMMgr:
if not validator.is_valid_email(email):
raise validator.InvalidValueException('email', email)
self.conf['common']['email'] = email
- confupdater.update_email(email)
if gmaps_api_key != None:
# Update Google Maps API key
self.conf['common']['gmaps-api-key'] = gmaps_api_key
- confupdater.update_gmaps_api_key(gmaps_api_key)
# Save config to file
self.save_conf()
- # Restart currently running apps in order to update config
for app in self.conf['apps']:
+ # Restart currently running apps in order to update their config
if tools.is_service_started(app):
tools.restart_service(app)
def update_password(self, oldpassword, newpassword):
# Update LUKS password and adminpwd for WSGI application
- tools.update_luks_password(oldpassword, newpassword)
+ input = '{}\n{}'.format(oldpassword, newpassword).encode()
+ subprocess.run(['cryptsetup', 'luksChangeKey', '/dev/sda2'], input=input, check=True)
+ # Update bcrypt-hashed password in config
self.conf['host']['adminpwd'] = tools.adminpwd_hash(newpassword)
# Save config to file
self.save_conf()
diff --git a/basic/srv/vm/mgr/confupdater.py b/basic/srv/vm/mgr/confupdater.py
deleted file mode 100644
index 68e8f67..0000000
--- a/basic/srv/vm/mgr/confupdater.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# TODO: Rewrite back to individual files
-
-import os
-import shutil
-import subprocess
-
-from . import tools
-
-TMP_FILE = '/tmp/confupdater.tmp'
-
-def replace_file_line(filename, oldline, newline):
- with open(filename, 'r') as conf, open(TMP_FILE, 'w') as tmp:
- for line in conf:
- # Find line starting with oldline
- if line.startswith(oldline):
- # Replace te line with oldline, newline, \n (to not repeat the oldline in newline)
- tmp.write(oldline)
- tmp.write(newline)
- tmp.write('\n')
- # Dump the rest of the file and break the loop
- tmp.write(conf.read())
- break
- else:
- tmp.write(line)
- # Copy the file contents to the original file (preserves permissions of the original file)
- shutil.copyfile(TMP_FILE, filename)
- os.unlink(TMP_FILE)
-
-def run_mysql_query(query, database):
- maria_started = tools.is_service_started('mariadb')
- if not maria_started:
- tools.start_service('mariadb')
- subprocess.run(['lxc-attach', 'mariadb', '--', 'mysql', '-e', query, database])
- if not maria_started:
- tools.stop_service('mariadb')
-
-def app_exists(app):
- return os.path.exists(os.path.join('/srv/', app))
-
-def update_gmaps_api_key(api_key):
- # CKAN
- if app_exists('ckan'):
- replace_file_line('/srv/ckan/conf/ckan.ini', 'ckanext.geoview.gapi_key = ', api_key)
- # Crisis Cleanup
- if app_exists('crisiscleanup'):
- replace_file_line('/srv/crisiscleanup/conf/boot.rb', 'ENV[\'GOOGLE_MAPS_API_KEY\'] = ', api_key)
- # Pan.do/ra
- if app_exists('pandora'):
- replace_file_line('/srv/pandora/conf/local_settings.py', 'GOOGLE_API_KEY = ', '\'{}\''.format(api_key))
- # Sahana
- if app_exists('sahana'):
- replace_file_line('/srv/sahana/conf/000_config.py', 'settings.gis.api_google = ', '"{}"'.format(api_key))
- # Sahana Demo
- if app_exists('sahana-demo'):
- replace_file_line('/srv/sahana-demo/conf/000_config.py', 'settings.gis.api_google = ', '"{}"'.format(api_key))
- # SAMBRO
- if app_exists('sambro'):
- replace_file_line('/srv/sambro/conf/000_config.py', 'settings.gis.api_google = ', '"{}"'.format(api_key))
- # Sigmah
- if app_exists('sigmah'):
- replace_file_line('/srv/sigmah/conf/sigmah.properties', 'maps.key=', api_key)
- # Ushahidi
- if app_exists('ushahidi'):
- replace_file_line('/srv/ushahidi/conf/config.json', ' "google_analytics_id": ', '"{}"'.format(api_key))
-
-def update_email(email):
- # CKAN
- if app_exists('ckan'):
- replace_file_line('/srv/ckan/conf/ckan.ini', 'smtp.mail_from = ', email)
- replace_file_line('/srv/ckan-datapusher/conf/datapusher_settings.py', 'FROM_EMAIL = ', '\'{}\''.format(email))
- # Crisis Cleanup
- if app_exists('crisiscleanup'):
- replace_file_line('/srv/crisiscleanup/conf/initializers/devise.rb', ' config.mailer_sender = ', '\'{}\''.format(email))
- # CTS
- if app_exists('cts'):
- replace_file_line('/srv/cts/conf/spotter.py', 'SERVER_EMAIL = ', '\'{}\''.format(email))
- # GNU Health
- if app_exists('gnuhealth'):
- replace_file_line('/srv/gnuhealth/conf/trytond.conf', 'from = ', email)
- # KanBoard
- if app_exists('kanboard'):
- replace_file_line('/srv/kanboard/conf/config.php', 'define(\'MAIL_FROM\', ', '\'{}\');'.format(email))
- # Mifos X
- if app_exists('mifosx'):
- query = 'UPDATE `c_external_service_properties` SET `value` = "{}" WHERE `external_service_id` = 2 and `name` LIKE "username";'.format(email)
- run_mysql_query(query, 'mifostenant-default')
- # Sahana
- if app_exists('sahana'):
- replace_file_line('/srv/sahana/conf/000_config.py', 'settings.mail.sender = ', '"{}"'.format(email))
- replace_file_line('/srv/sahana/conf/000_config.py', 'settings.mail.approver = ', '"{}"'.format(email))
- # Sahana Demo
- if app_exists('sahana-demo'):
- replace_file_line('/srv/sahana-demo/conf/000_config.py', 'settings.mail.sender = ', '"{}"'.format(email))
- replace_file_line('/srv/sahana-demo/conf/000_config.py', 'settings.mail.approver = ', '"{}"'.format(email))
- # SAMBRO
- if app_exists('sambro'):
- replace_file_line('/srv/sambro/conf/000_config.py', 'settings.mail.sender = ', '"{}"'.format(email))
- replace_file_line('/srv/sambro/conf/000_config.py', 'settings.mail.approver = ', '"{}"'.format(email))
- # SeedDMS
- if app_exists('seeddms'):
- replace_file_line('/srv/seeddms/conf/settings.xml', ' '.format(email))
- # Sigmah
- if app_exists('sigmah'):
- replace_file_line('/srv/sigmah/conf/sigmah.properties', 'mail.from.address=', email)
- replace_file_line('/srv/sigmah/conf/sigmah.properties', 'mail.support.to=', email)
- # Ushahidi
- if app_exists('ushahidi'):
- email_json = '{{\\"incoming_type\\":\\"IMAP\\",\\"incoming_server\\":\\"localhost\\",\\"incoming_port\\":143,\\"incoming_security\\":\\"None\\",\\"incoming_username\\":\\"{}\\",\\"incoming_password\\":\\"password\\",\\"outgoing_type\\":\\"SMTP\\",\\"outgoing_server\\":\\"host\\",\\"outgoing_port\\":25,\\"outgoing_security\\":\\"None\\",\\"outgoing_username\\":\\"{}\\",\\"outgoing_password\\":\\"password\\",\\"from\\":\\"{}\\",\\"from_name\\":\\"Ushahidi\\"}}'.format(email, email, email)
- query = 'UPDATE `config` SET `config_value` = "{}" WHERE `group_name` LIKE "data-provider" AND `config_key` LIKE "email";'.format(email_json)
- run_mysql_query(query, 'ushahidi')
- query = 'UPDATE `config` SET `config_value` = "\\"{}\\"" WHERE `group_name` LIKE "site" AND `config_key` LIKE "email";'.format(email)
- run_mysql_query(query, 'ushahidi')
-
-def update_url(domain, port):
- host = tools.compile_url(domain, port, None)
- # CKAN
- if app_exists('ckan'):
- replace_file_line('/srv/ckan/conf/ckan.ini', 'ckan.site_url = ', 'https://ckan.{}'.format(host))
- # Mifos X
- if app_exists('mifosx'):
- replace_file_line('/srv/mifosx/conf/server.xml', ' proxyName=', '"{}"'.format(domain))
- replace_file_line('/srv/mifosx/conf/server.xml', ' proxyPort=', '"{}"'.format(port))
- # Motech
- if app_exists('motech'):
- replace_file_line('/srv/motech/conf/config/motech-settings.properties', 'server.url=', 'https://motech.{}'.format(host))
- # OpenDataKit
- if app_exists('opendatakit'):
- replace_file_line('/srv/opendatakit/conf/server.xml', ' proxyName=', '"{}"'.format(domain))
- replace_file_line('/srv/opendatakit/conf/server.xml', ' proxyPort=', '"{}"'.format(port))
- replace_file_line('/srv/opendatakit/conf/security.properties', 'security.server.securePort=', port)
- # Pan.do/ra
- if app_exists('pandora'):
- replace_file_line('/srv/pandora/conf/config.jsonc', ' "url": ', '"pandora.{}"'.format(host))
- # Sahana
- if app_exists('sahana'):
- replace_file_line('/srv/sahana/conf/000_config.py', 'settings.base.public_url = ', '"https://sahana.{}"'.format(host))
- # Sahana Demo
- if app_exists('sahana-demo'):
- replace_file_line('/srv/sahana-demo/conf/000_config.py', 'settings.base.public_url = ', '"https://sahana-demo.{}"'.format(host))
- # SAMBRO
- if app_exists('sambro'):
- replace_file_line('/srv/sambro/conf/000_config.py', 'settings.base.public_url = ', '"https://sambro.{}"'.format(host))
- # Ushahidi
- if app_exists('ushahidi'):
- replace_file_line('/srv/ushahidi/conf/config.json', ' "backend_url": ', '"https://ush.{}/platform",'.format(host))
- api_url = '\\"https:\\\\/\\\\/ush.{}\\\\/platform\\\\/api\\\\/v3\\\\/config\\\\/data-provider\\"'.format(host)
- query = 'UPDATE `config` SET `config_value` = "{}" WHERE `group_name` LIKE "data-provider" AND `config_key` LIKE "url";'.format(api_url)
- run_mysql_query(query, 'ushahidi')
diff --git a/basic/srv/vm/mgr/tools.py b/basic/srv/vm/mgr/tools.py
index 59c8373..6252b51 100644
--- a/basic/srv/vm/mgr/tools.py
+++ b/basic/srv/vm/mgr/tools.py
@@ -10,22 +10,20 @@ import socket
import ssl
import subprocess
-NULL_IP = '[100::1]'
-
def compile_url(domain, port, proto='https'):
port = '' if (proto == 'https' and port == '443') or (proto == 'http' and port == '80') else ':{}'.format(port)
host = '{}{}'.format(domain, port)
return '{}://{}'.format(proto, host) if proto is not None else host
def get_local_ipv4():
- # Return first routable IPv4 address
+ # Return first routable IPv4 address of the VM (container host)
try:
return subprocess.run(['/sbin/ip', 'route', 'get', '1'], check=True, stdout=subprocess.PIPE).stdout.decode().split()[-1]
except:
return None
def get_local_ipv6():
- # Return first routable IPv6 address
+ # Return first routable IPv6 address of the VM (container host)
try:
return subprocess.run(['/sbin/ip', 'route', 'get', '2003::'], check=True, stdout=subprocess.PIPE).stdout.decode().split()[-3]
except:
@@ -90,7 +88,7 @@ def restart_service(service):
subprocess.run(['/sbin/service', service, 'restart'])
def reload_nginx():
- subprocess.run(['/sbin/service', 'nginx', 'reload'])
+ subprocess.run(['/usr/sbin/nginx', '-s', 'reload'])
def restart_nginx():
restart_service('nginx')
@@ -107,10 +105,6 @@ def adminpwd_hash(password):
def adminpwd_verify(password, hash):
return bcrypt.checkpw(password.encode(), hash.encode())
-def update_luks_password(oldpassword, newpassword):
- input = '{}\n{}'.format(oldpassword, newpassword).encode()
- subprocess.run(['cryptsetup', 'luksChangeKey', '/dev/sda2'], input=input, check=True)
-
def shutdown_vm():
subprocess.run(['/sbin/poweroff'])
@@ -142,14 +136,6 @@ def update_hosts_lease(ip, app):
with open('/etc/hosts', 'w') as fd:
fd.writelines(hosts)
-def get_container_ip(app):
- # Return an IP of a container. If the container doesn't exist, return address from IPv6 discard prefix instead
- with open('/etc/hosts', 'r') as fd:
- for line in fd:
- if line.strip().endswith(' {}'.format(app)):
- return line.split()[0]
- return NULL_IP
-
def set_container_ip(pid, ip):
# Set IP in container based on PID given via lxc.hook.start-host hook
cmd = 'ip addr add {}/16 broadcast 172.17.255.255 dev eth0 && ip route add default via 172.17.0.1'.format(ip)
diff --git a/ckan-datapusher/setup.sh b/ckan-datapusher/setup.sh
index 114ce0c..a8cf4bd 100755
--- a/ckan-datapusher/setup.sh
+++ b/ckan-datapusher/setup.sh
@@ -5,6 +5,7 @@ SOURCE_DIR=$(realpath $(dirname "${0}"))/setup
# Configure CKAN DataPusher
mkdir -p /srv/ckan-datapusher/conf /srv/ckan-datapusher/data
+cp ${SOURCE_DIR}/srv/ckan-datapusher/update-conf.sh /srv/ckan-datapusher/update-conf.sh
cp ${SOURCE_DIR}/srv/ckan-datapusher/conf/datapusher.wsgi /srv/ckan-datapusher/conf/datapusher.wsgi
cp ${SOURCE_DIR}/srv/ckan-datapusher/conf/datapusher_settings.py /srv/ckan-datapusher/conf/datapusher_settings.py
chown -R 8004:8004 /srv/ckan-datapusher/data
diff --git a/ckan-datapusher/setup/srv/ckan-datapusher/update-conf.sh b/ckan-datapusher/setup/srv/ckan-datapusher/update-conf.sh
new file mode 100755
index 0000000..766ab74
--- /dev/null
+++ b/ckan-datapusher/setup/srv/ckan-datapusher/update-conf.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+sed -i "s|\(^FROM_EMAIL = \).*|\1'${EMAIL}'|" /srv/ckan-datapusher/conf/datapusher_settings.py
diff --git a/ckan/setup.sh b/ckan/setup.sh
index fd222d5..3f9f715 100755
--- a/ckan/setup.sh
+++ b/ckan/setup.sh
@@ -22,6 +22,7 @@ service solr restart
# Configure CKAN
mkdir -p /srv/ckan/conf /srv/ckan/data
+cp ${SOURCE_DIR}/srv/ckan/update-conf.sh /srv/ckan/update-conf.sh
export CKAN_SECRET=$(head -c 18 /dev/urandom | base64)
export CKAN_UUID=$(cat /proc/sys/kernel/random/uuid)
envsubst <${SOURCE_DIR}/srv/ckan/conf/ckan.ini >/srv/ckan/conf/ckan.ini
diff --git a/ckan/setup/srv/ckan/update-conf.sh b/ckan/setup/srv/ckan/update-conf.sh
new file mode 100755
index 0000000..9a13f3e
--- /dev/null
+++ b/ckan/setup/srv/ckan/update-conf.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+HOST="${DOMAIN}"
+[ "${PORT}" != "443" ] && HOST="${DOMAIN}:${PORT}"
+sed -i "s|\(^ckan\.site_url = \).*|\1https://${HOST}|" /srv/ckan/conf/ckan.ini
+
+sed -i "s|\(^smtp\.mail_from = \).*|\1${EMAIL}|" /srv/ckan/conf/ckan.ini
+sed -i "s|\(^ckanext\.geoview\.gapi_key = \).*|\1${GMAPS_API_KEY}|" /srv/ckan/conf/ckan.ini
diff --git a/crisiscleanup/setup.sh b/crisiscleanup/setup.sh
index 82aaf18..ed54eed 100755
--- a/crisiscleanup/setup.sh
+++ b/crisiscleanup/setup.sh
@@ -16,6 +16,7 @@ chown 8005:8005 /srv/crisiscleanup/conf
cp -r /var/lib/lxc/crisiscleanup/crisiscleanup/srv/crisiscleanup/config/. /srv/crisiscleanup/conf
# Configure CrisisCleanup
+cp ${SOURCE_DIR}/srv/crisiscleanup/update-conf.sh /srv/crisiscleanup/update-conf.sh
export CRISISCLEANUP_ADMIN_USER="Admin"
export CRISISCLEANUP_ADMIN_EMAIL="admin@example.com"
export CRISISCLEANUP_ADMIN_PWD=$(head -c 12 /dev/urandom | base64)
diff --git a/crisiscleanup/setup/srv/crisiscleanup/update-conf.sh b/crisiscleanup/setup/srv/crisiscleanup/update-conf.sh
new file mode 100755
index 0000000..744fc35
--- /dev/null
+++ b/crisiscleanup/setup/srv/crisiscleanup/update-conf.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+sed -i "s|\(^ config\.mailer_sender = \).*|\1'${EMAIL}'|" /srv/crisiscleanup/conf/initializers/devise.rb
+sed -i "s|\(^ENV['GOOGLE_MAPS_API_KEY'] = \).*|\1${GMAPS_API_KEY}|" /srv/crisiscleanup/conf/boot.rb
diff --git a/cts/setup.sh b/cts/setup.sh
index 0e28ae6..3c57745 100755
--- a/cts/setup.sh
+++ b/cts/setup.sh
@@ -15,6 +15,7 @@ mkdir -p /srv/cts/conf
cp /var/lib/lxc/cts/cts/srv/cts/cts/settings/base.py /srv/cts/conf
# Configure CTS
+cp ${SOURCE_DIR}/srv/cts/update-conf.sh /srv/cts/update-conf.sh
export CTS_SECRET=$(head -c 26 /dev/urandom | base64)
envsubst <${SOURCE_DIR}/srv/cts/conf/spotter.py >/srv/cts/conf/spotter.py
touch /srv/cts/conf/__init__.py
diff --git a/cts/setup/srv/cts/update-conf.sh b/cts/setup/srv/cts/update-conf.sh
new file mode 100755
index 0000000..9cea8da
--- /dev/null
+++ b/cts/setup/srv/cts/update-conf.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+sed -i "s|\(^SERVER_EMAIL = \).*|\1'${EMAIL}'|" /srv/cts/conf/spotter.py
diff --git a/gnuhealth/setup.sh b/gnuhealth/setup.sh
index 21e5eb8..5e5beaa 100755
--- a/gnuhealth/setup.sh
+++ b/gnuhealth/setup.sh
@@ -12,6 +12,7 @@ envsubst <${SOURCE_DIR}/createdb.sql | lxc-attach -u 5432 -g 5432 postgres -- ps
# Configure GNU Health
mkdir -p /srv/gnuhealth/conf/
+cp ${SOURCE_DIR}/srv/gnuhealth/update-conf.sh /srv/gnuhealth/update-conf.sh
envsubst <${SOURCE_DIR}/srv/gnuhealth/conf/trytond.conf >/srv/gnuhealth/conf/trytond.conf
# Populate database
diff --git a/gnuhealth/setup/srv/gnuhealth/update-conf.sh b/gnuhealth/setup/srv/gnuhealth/update-conf.sh
new file mode 100755
index 0000000..57e4043
--- /dev/null
+++ b/gnuhealth/setup/srv/gnuhealth/update-conf.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+sed -i "s|\(^from = \).*|\1${EMAIL}|" /srv/gnuhealth/conf/trytond.conf
diff --git a/kanboard/setup.sh b/kanboard/setup.sh
index 622ff49..6e00955 100755
--- a/kanboard/setup.sh
+++ b/kanboard/setup.sh
@@ -13,6 +13,7 @@ cat /var/lib/lxc/kanboard/kanboard/srv/kanboard/app/Schema/Sql/postgres.sql | lx
# Configure Kanboard
mkdir -p /srv/kanboard/conf /srv/kanboard/data
+cp ${SOURCE_DIR}/srv/kanboard/update-conf.sh /srv/kanboard/update-conf.sh
chown -R 8009:8009 /srv/kanboard/data
envsubst <${SOURCE_DIR}/srv/kanboard/conf/config.php >/srv/kanboard/conf/config.php
export KANBOARD_ADMIN_USER=admin
diff --git a/kanboard/setup/srv/kanboard/update-conf.sh b/kanboard/setup/srv/kanboard/update-conf.sh
new file mode 100755
index 0000000..4b8d77b
--- /dev/null
+++ b/kanboard/setup/srv/kanboard/update-conf.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+sed -i "s|\(^define('MAIL_FROM', \).*|\1'${EMAIL}');|" /srv/kanboard/conf/config.php
diff --git a/mifosx/setup.sh b/mifosx/setup.sh
index 870fafe..3e09ab2 100755
--- a/mifosx/setup.sh
+++ b/mifosx/setup.sh
@@ -16,6 +16,7 @@ envsubst <${SOURCE_DIR}/schemapwd.sql | lxc-attach mariadb -- mysql mifosplatfor
# Configure Mifos X
mkdir -p /srv/mifosx/conf
+cp ${SOURCE_DIR}/srv/mifosx/update-conf.sh /srv/mifosx/update-conf.sh
envsubst <${SOURCE_DIR}/srv/mifosx/conf/context.xml >/srv/mifosx/conf/context.xml
cp ${SOURCE_DIR}/srv/mifosx/conf/server.xml /srv/mifosx/conf/server.xml
diff --git a/mifosx/setup/srv/mifosx/update-conf.sh b/mifosx/setup/srv/mifosx/update-conf.sh
new file mode 100755
index 0000000..d4f338e
--- /dev/null
+++ b/mifosx/setup/srv/mifosx/update-conf.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+sed -i "s|\(^\s\+proxyName=\).*|\1\"${DOMAIN}\"|" /srv/mifosx/conf/server.xml
+sed -i "s|\(^\s\+proxyPort=\).*|\1\"${PORT}\"|" /srv/mifosx/conf/server.xml
+
+QUERY="UPDATE \`c_external_service_properties\` SET `value` = '${EMAIL}' WHERE \`external_service_id\` = 2 and \`name\` LIKE 'username'"
+lxc-attach mariadb -- mysql -e "${QUERY}" mifostenant-default
diff --git a/motech/setup.sh b/motech/setup.sh
index 0a02aaf..183a762 100755
--- a/motech/setup.sh
+++ b/motech/setup.sh
@@ -13,6 +13,7 @@ envsubst <${SOURCE_DIR}/createdb.sql | lxc-attach -u 5432 -g 5432 postgres -- ps
# Configure Motech
mkdir -p /srv/motech/conf/config/org.motechproject.motech-platform-email
+cp ${SOURCE_DIR}/srv/motech/update-conf.sh /srv/motech/update-conf.sh
envsubst <${SOURCE_DIR}/srv/motech/conf/config/bootstrap.properties >/srv/motech/conf/config/bootstrap.properties
cp ${SOURCE_DIR}/srv/motech/conf/config-locations.properties /srv/motech/conf/config-locations.properties
cp ${SOURCE_DIR}/srv/motech/conf/config/motech-settings.properties /srv/motech/conf/config/motech-settings.properties
diff --git a/motech/setup/srv/motech/update-conf.sh b/motech/setup/srv/motech/update-conf.sh
new file mode 100755
index 0000000..3626871
--- /dev/null
+++ b/motech/setup/srv/motech/update-conf.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+HOST="${DOMAIN}"
+[ "${PORT}" != "443" ] && HOST="${DOMAIN}:${PORT}"
+sed -i "s|\(^server\.url=\).*|\1https://motech.${HOST}|" /srv/motech/conf/config/motech-settings.properties
diff --git a/opendatakit/setup.sh b/opendatakit/setup.sh
index 6784b9c..27773ac 100755
--- a/opendatakit/setup.sh
+++ b/opendatakit/setup.sh
@@ -11,9 +11,8 @@ export OPENDATAKIT_PWD=$(head -c 18 /dev/urandom | base64)
envsubst <${SOURCE_DIR}/createdb.sql | lxc-attach -u 5432 -g 5432 postgres -- psql
# Configure OpenDataKit
-export OPENDATAKIT_ADMIN_USER=admin
-export OPENDATAKIT_ADMIN_REALM=spotter
mkdir -p /srv/opendatakit/conf
+cp ${SOURCE_DIR}/srv/opendatakit/update-conf.sh /srv/opendatakit/update-conf.sh
envsubst <${SOURCE_DIR}/srv/opendatakit/conf/jdbc.properties >/srv/opendatakit/conf/jdbc.properties
envsubst <${SOURCE_DIR}/srv/opendatakit/conf/security.properties >/srv/opendatakit/conf/security.properties
cp ${SOURCE_DIR}/srv/opendatakit/conf/server.xml /srv/opendatakit/conf/server.xml
@@ -31,6 +30,8 @@ done
service opendatakit stop
# Update admin account
+export OPENDATAKIT_ADMIN_USER=admin
+export OPENDATAKIT_ADMIN_REALM=spotter
export OPENDATAKIT_ADMIN_PWD=$(head -c 12 /dev/urandom | base64)
export OPENDATAKIT_ADMIN_SALT=$(head -c 4 /dev/urandom | hexdump -e '"%x"') # Must be 8 characters
export OPENDATAKIT_ADMIN_BASIC_HASH=$(echo -n "${OPENDATAKIT_ADMIN_PWD}{${OPENDATAKIT_ADMIN_SALT}}" | sha1sum | tr -d " -")
diff --git a/opendatakit/setup/srv/opendatakit/update-conf.sh b/opendatakit/setup/srv/opendatakit/update-conf.sh
new file mode 100755
index 0000000..0d84c5e
--- /dev/null
+++ b/opendatakit/setup/srv/opendatakit/update-conf.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+sed -i "s|\(^\s\+proxyName=\).*|\1\"${DOMAIN}\"|" /srv/mifosx/conf/server.xml
+sed -i "s|\(^\s\+proxyPort=\).*|\1\"${PORT}\"|" /srv/mifosx/conf/server.xml
+sed -i "s|\(^security\.server\.securePort=\).*|\1${PORT}|" /srv/opendatakit/conf/security.properties
diff --git a/pandora/setup.sh b/pandora/setup.sh
index 5ae6dad..0c79398 100755
--- a/pandora/setup.sh
+++ b/pandora/setup.sh
@@ -19,6 +19,7 @@ lxc-attach rabbitmq -- rabbitmqctl set_permissions -p /pandora pandora ".*" ".*"
# Configure Pandora
mkdir -p /srv/pandora/conf /srv/pandora/data
+cp ${SOURCE_DIR}/srv/pandora/update-conf.sh /srv/pandora/update-conf.sh
chown 8002:8002 /srv/pandora/data
# Copy customized configuration if VANILLA environment variable is not set, else use the default pandora config
if [ ${VANILLA:-0} -eq 0 ]; then
diff --git a/pandora/setup/srv/pandora/update-conf.sh b/pandora/setup/srv/pandora/update-conf.sh
new file mode 100755
index 0000000..a68d15b
--- /dev/null
+++ b/pandora/setup/srv/pandora/update-conf.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+HOST="${DOMAIN}"
+[ "${PORT}" != "443" ] && HOST="${DOMAIN}:${PORT}"
+sed -i "s|\(^\s\+\"url\": \).*|\1\"pandora.${HOST}\"|" /srv/pandora/conf/config.jsonc
+
+sed -i "s|\(^GOOGLE_API_KEY = \).*|\1'${GMAPS_API_KEY}'|" /srv/pandora/conf/local_settings.py
diff --git a/sahana-demo/setup.sh b/sahana-demo/setup.sh
index 58c6cf0..7c21092 100755
--- a/sahana-demo/setup.sh
+++ b/sahana-demo/setup.sh
@@ -18,6 +18,7 @@ cp -rp /var/lib/lxc/sahana/sahana/srv/web2py/applications/eden/models/. /srv/sah
cp -rp /var/lib/lxc/sahana/sahana/srv/web2py/applications/eden/modules/templates/${TEMPLATE}/. /srv/sahana-demo/data/${TEMPLATE}
# Configure Sahana
+cp ${SOURCE_DIR}/srv/sahana-demo/update-conf.sh /srv/sahana-demo/update-conf.sh
export SAHANADEMO_HMAC=$(head -c 18 /dev/urandom | base64)
export SAHANADEMO_ADMIN_USER=admin@example.com
export SAHANADEMO_ADMIN_PWD=$(head -c 12 /dev/urandom | base64)
diff --git a/sahana-demo/setup/srv/sahana-demo/update-conf.sh b/sahana-demo/setup/srv/sahana-demo/update-conf.sh
new file mode 100755
index 0000000..34b7687
--- /dev/null
+++ b/sahana-demo/setup/srv/sahana-demo/update-conf.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+HOST="${DOMAIN}"
+[ "${PORT}" != "443" ] && HOST="${PORT}:${DOMAIN}"
+sed -i "s|\(^settings\.base\.public_url = \).*|\1\"https://sahana.${HOST}\"|" /srv/sahana-demo/conf/000_config.py
+
+sed -i "s|\(^settings\.mail\.sender = \).*|\1\"${EMAIL}\"|" /srv/sahana-demo/conf/000_config.py
+sed -i "s|\(^settings\.mail\.approver = \).*|\1\"${EMAIL}\"|" /srv/sahana-demo/conf/000_config.py
+sed -i "s|\(^settings\.gis\.api_google = \).*|\1\"${GMAPS_API_KEY}\"|" /srv/sahana-demo/conf/000_config.py
diff --git a/sahana/setup.sh b/sahana/setup.sh
index de14d3e..8b2775f 100755
--- a/sahana/setup.sh
+++ b/sahana/setup.sh
@@ -20,6 +20,7 @@ cp -r ${SOURCE_DIR}/srv/sahana/data/Spotter /srv/sahana/data/
chown -R 8001:8001 /srv/sahana/data
# Configure Sahana
+cp ${SOURCE_DIR}/srv/sahana/update-conf.sh /srv/sahana/update-conf.sh
export SAHANA_HMAC=$(head -c 18 /dev/urandom | base64)
export SAHANA_ADMIN_USER=admin@example.com
export SAHANA_ADMIN_PWD=$(head -c 12 /dev/urandom | base64)
diff --git a/sahana/setup/srv/sahana/update-conf.sh b/sahana/setup/srv/sahana/update-conf.sh
new file mode 100755
index 0000000..93690ce
--- /dev/null
+++ b/sahana/setup/srv/sahana/update-conf.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+HOST="${DOMAIN}"
+[ "${PORT}" != "443" ] && HOST="${PORT}:${DOMAIN}"
+sed -i "s|\(^settings\.base\.public_url = \).*|\1\"https://sahana.${HOST}\"|" /srv/sahana/conf/000_config.py
+
+sed -i "s|\(^settings\.mail\.sender = \).*|\1\"${EMAIL}\"|" /srv/sahana/conf/000_config.py
+sed -i "s|\(^settings\.mail\.approver = \).*|\1\"${EMAIL}\"|" /srv/sahana/conf/000_config.py
+sed -i "s|\(^settings\.gis\.api_google = \).*|\1\"${GMAPS_API_KEY}\"|" /srv/sahana/conf/000_config.py
diff --git a/sambro/setup.sh b/sambro/setup.sh
index 7bb6466..1d7e98d 100755
--- a/sambro/setup.sh
+++ b/sambro/setup.sh
@@ -17,6 +17,7 @@ cp -rp /var/lib/lxc/sahana/sahana/srv/web2py/applications/eden/models/. /srv/sah
cp -rp /var/lib/lxc/sahana/sahana/srv/web2py/applications/eden/modules/templates/SAMBRO/. /srv/sahana-demo/data/SAMBRO
# Configure SAMBRO
+cp ${SOURCE_DIR}/srv/sambro/update-conf.sh /srv/sambro/update-conf.sh
export SAMBRO_HMAC=$(head -c 18 /dev/urandom | base64)
export SAMBRO_ADMIN_USER=admin@example.com
export SAMBRO_ADMIN_PWD=$(head -c 12 /dev/urandom | base64)
diff --git a/sambro/setup/srv/sambro/update-conf.sh b/sambro/setup/srv/sambro/update-conf.sh
new file mode 100755
index 0000000..5cb0597
--- /dev/null
+++ b/sambro/setup/srv/sambro/update-conf.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+HOST="${DOMAIN}"
+[ "${PORT}" != "443" ] && HOST="${PORT}:${DOMAIN}"
+sed -i "s|\(^settings\.base\.public_url = \).*|\1\"https://sahana.${HOST}\"|" /srv/sambro/conf/000_config.py
+
+sed -i "s|\(^settings\.mail\.sender = \).*|\1\"${EMAIL}\"|" /srv/sambro/conf/000_config.py
+sed -i "s|\(^settings\.mail\.approver = \).*|\1\"${EMAIL}\"|" /srv/sambro/conf/000_config.py
+sed -i "s|\(^settings\.gis\.api_google = \).*|\1\"${GMAPS_API_KEY}\"|" /srv/sambro/conf/000_config.py
diff --git a/seeddms/setup.sh b/seeddms/setup.sh
index aa4a549..5222dea 100755
--- a/seeddms/setup.sh
+++ b/seeddms/setup.sh
@@ -19,6 +19,7 @@ cp -rp /var/lib/lxc/seeddms/seeddms/srv/seeddms/data/. /srv/seeddms/data
chown -R 8010:8010 /srv/seeddms/data
# Configure SeedDMS
+cp ${SOURCE_DIR}/srv/seeddms/update-conf.sh /srv/seeddms/update-conf.sh
envsubst <${SOURCE_DIR}/srv/seeddms/conf/settings.xml >/srv/seeddms/conf/settings.xml
export SEEDDMS_ADMIN_USER=admin
export SEEDDMS_ADMIN_PWD=$(head -c 12 /dev/urandom | base64)
diff --git a/seeddms/setup/srv/seeddms/update-conf.sh b/seeddms/setup/srv/seeddms/update-conf.sh
new file mode 100755
index 0000000..f5f590f
--- /dev/null
+++ b/seeddms/setup/srv/seeddms/update-conf.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+sed -i "s|\(^\s\+|" /srv/seeddms/conf/settings.xml
diff --git a/sigmah/setup.sh b/sigmah/setup.sh
index 043f866..406fba0 100755
--- a/sigmah/setup.sh
+++ b/sigmah/setup.sh
@@ -12,6 +12,7 @@ envsubst <${SOURCE_DIR}/createdb.sql | lxc-attach -u 5432 -g 5432 postgres -- ps
# Configure Sigmah
mkdir -p /srv/sigmah/conf /srv/sigmah/data/files /srv/sigmah/data/archives
+cp ${SOURCE_DIR}/srv/sigmah/update-conf.sh /srv/sigmah/update-conf.sh
chown -R 8011:8011 /srv/sigmah/data
envsubst <${SOURCE_DIR}/srv/sigmah/conf/persistence.xml >/srv/sigmah/conf/persistence.xml
cp ${SOURCE_DIR}/srv/sigmah/conf/sigmah.properties /srv/sigmah/conf/sigmah.properties
diff --git a/sigmah/setup/srv/sigmah/update-conf.sh b/sigmah/setup/srv/sigmah/update-conf.sh
new file mode 100755
index 0000000..44561f2
--- /dev/null
+++ b/sigmah/setup/srv/sigmah/update-conf.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+sed -i "s|\(^mail\.from\.address=\).*|\1${EMAIL}|" /srv/sigmah/conf/sigmah.properties
+sed -i "s|\(^mail\.support\.to=\).*|\1${EMAIL}|" /srv/sigmah/conf/sigmah.properties
+sed -i "s|\(^maps\.key=\).*|\1${GMAPS_API_KEY}|" /srv/sigmah/conf/sigmah.properties
diff --git a/ushahidi/setup.sh b/ushahidi/setup.sh
index 2748c78..0ea34a2 100755
--- a/ushahidi/setup.sh
+++ b/ushahidi/setup.sh
@@ -12,6 +12,7 @@ envsubst <${SOURCE_DIR}/createdb.sql | lxc-attach mariadb -- mysql
# Configure Ushahidi
mkdir -p /srv/ushahidi/conf /srv/ushahidi/data
+cp ${SOURCE_DIR}/srv/ushahidi/update-conf.sh /srv/ushahidi/update-conf.sh
chown 8014:8014 /srv/ushahidi/data
envsubst <${SOURCE_DIR}/srv/ushahidi/conf/env >/srv/ushahidi/conf/env
cp ${SOURCE_DIR}/srv/ushahidi/conf/config.json /srv/ushahidi/conf/config.json
diff --git a/ushahidi/setup/srv/ushahidi/update-conf.sh b/ushahidi/setup/srv/ushahidi/update-conf.sh
new file mode 100755
index 0000000..25f0d77
--- /dev/null
+++ b/ushahidi/setup/srv/ushahidi/update-conf.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+HOST="${DOMAIN}"
+[ "${PORT}" != "443" ] && HOST="${DOMAIN}:${PORT}"
+sed -i "s|\(^\s\+\"backend_url\": \).*|\1\"https://ush.${HOST}/platform\"|" /srv/ushahidi/conf/config.json
+API_URL="\"https:\\\/\\\/ush.${HOST}\\\/platform\\\/api\\\/v3\\\/config\\\/data-provider\""
+QUERY="UPDATE \`config\` SET \`config_value\` = '${API_URL}' WHERE \`group_name\` LIKE 'data-provider' AND \`config_key\` LIKE 'url'"
+lxc-attach mariadb -- mysql -e "${QUERY}" ushahidi
+
+JSON="{\"incoming_type\":\"IMAP\",\"incoming_server\":\"localhost\",\"incoming_port\":143,\"incoming_security\":\"None\",\"incoming_username\":\"${EMAIL}\",\"incoming_password\":\"password\",\"outgoing_type\":\"SMTP\",\"outgoing_server\":\"host\",\"outgoing_port\":25,\"outgoing_security\":\"None\",\"outgoing_username\":\"${EMAIL}\",\"outgoing_password\":\"password\",\"from\":\"${EMAIL}\",\"from_name\":\"Ushahidi\"}"
+QUERY="UPDATE \`config\` SET \`config_value\` = '${JSON}' WHERE \`group_name\` LIKE 'data-provider' AND \`config_key\` LIKE 'email'"
+lxc-attach mariadb -- mysql -e "${QUERY}" ushahidi
+QUERY="UPDATE \`config\` SET \`config_value\` = '\"${EMAIL}\"' WHERE \`group_name\` LIKE 'site' AND \`config_key\` LIKE 'email'"
+lxc-attach mariadb -- mysql -e "${QUERY}" ushahidi
+sed -i "s|\(^\s\+\"google_analytics_id\": \).*|\1\"${GMAPS_API_KEY}\"|" /srv/ushahidi/conf/config.json