· 5 years ago · Sep 23, 2020, 02:50 AM
1#!/bin/bash
2
3# Make a pretty string for telling the user when things are done
4GREEN='\033[0;92m'
5NOCOLOR='\033[0m'
6DONE="${GREEN}DONE!${NOCOLOR}"
7
8# Determine script location
9SOURCE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
10
11# Load deployment configuration
12source $SOURCE_DIR/deploy.conf
13
14# Determine whether we are root or need to sudo
15SUDO=''
16if (( $(id -u) != 0 )); then
17 SUDO='sudo'
18fi
19
20# Prepare deploy location
21$SUDO mkdir -p "${DEPLOY_PATH}"
22
23# Add service user
24$SUDO useradd "${SERVICE_USER_NAME}" --comment "${SERVICE_USER_DESCRIPTION}" -r
25echo "Added service user: ${SERVICE_USER_NAME}"
26
27# Install system dependencies
28binExists() {
29 [ -x "$(command -vp $1)" ]
30}
31
32# Check for presence of systemd
33if ! binExists systemctl; then
34 printf 'Unsupported platform! Please use a distribution with systemd.'
35 exit 2
36fi
37
38# Install host system dependencies
39echo -n "Detected OS: "
40if binExists apt; then
41 PKGMGR='apt'
42 PKGDEL='purge'
43 if [ $DATABASE_CHOICE == 'mysql' ]; then
44 if [ "$(cat /etc/*release* | grep Debian)" ]; then
45 echo "Debian"
46 DATABASE='mariadb'
47 EXTRA_SYSTEM_PACKAGES='python3-dev libmariadb-dev python3-venv gcc'
48 else # Assume Ubuntu
49 echo "Ubuntu"
50 DATABASE='mysql'
51 EXTRA_SYSTEM_PACKAGES='python3-dev libmysqlclient-dev python3-venv gcc'
52 fi
53 elif [ $DATABASE_CHOICE == 'postgres' ]; then
54 DATABASE='postgresql'
55 EXTRA_SYSTEM_PACKAGES='python3-dev python3-venv'
56 fi
57elif binExists yum; then
58 echo "RHEL/CentOS"
59 PKGMGR='yum'
60 PKGDEL='remove'
61 if [ $DATABASE_CHOICE == 'mysql' ]; then
62 DATABASE='mariadb'
63 EXTRA_SYSTEM_PACKAGES='python3-devel mysql-devel gcc'
64 elif [ $DATABASE_CHOICE == 'postgres' ]; then
65 DATABASE='postgresql'
66 fi
67 # Check if SELinux present, if so include tools to manage it
68 if [ "$(cat /etc/sysconfig/selinux 2> /dev/null )" ]; then
69 if [ "$(rpm -q centos-release | grep -e '\-8\.[0-9]*\-')" ]; then
70 ext="-utils"
71 fi
72 EXTRA_SYSTEM_PACKAGES="${EXTRA_SYSTEM_PACKAGES} policycoreutils-python${ext}"
73 fi
74else
75 printf 'Unsupported platform! Please use one of these:\n* Debian \t* Ubuntu\n* CentOS\t* RHEL\n'
76 exit 2
77fi
78ALL_SYSTEM_PACKAGES="${EXTRA_SYSTEM_PACKAGES} ${DATABASE}-server python3 nginx openssl"
79echo "The following system packages will be installed: $ALL_SYSTEM_PACKAGES"
80echo -n "Installing system dependencies..."
81$SUDO $PKGMGR install -y $ALL_SYSTEM_PACKAGES &> /dev/null
82$SUDO systemctl enable --now $DATABASE &> /dev/null
83SERVER_USER="$(cat /etc/passwd | grep -Eo '(nginx|www-data)' | head -n1)"
84echo -e $DONE
85
86echo -n "Setting up database..."
87PASSWORD="$(openssl rand -base64 100 | grep -o '[[:alnum:]]' | head -n 42 | tr -d '\n')"
88if [ $DATABASE_CHOICE == 'mysql' ]; then
89 # Set up MySQL instance
90 $SUDO mysql -e "CREATE DATABASE ${DB_NAME};"
91 $SUDO mysql -e "GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost' IDENTIFIED BY '${PASSWORD}';"
92elif [ $DATABASE_CHOICE == 'postgres' ]; then
93 $SUDO postgresql-setup initdb
94 $SUDO su -c postgres "psql -c \"CREATE USER ${DB_USER} PASSWORD '${PASSWORD}'\""
95 $SUDO su -c postgres "psql -c \"CREATE DATABASE ${DB_NAME} OWNER = ${DB_USER}\""
96fi
97echo -e $DONE
98
99# Configure Django settings
100echo -n "Deploying Django project..."
101if [ $DATABASE_CHOICE == 'mysql' ]; then
102 DATABASE_CONFIG="
103 'default': {
104 'ENGINE': 'django.db.backends.mysql',
105 'NAME': '${DB_NAME}',
106 'USER': '${DB_USER}',
107 'PASSWORD': '${PASSWORD}',
108 'HOST': 'localhost',
109 'PORT': '3306',
110 },
111 "
112 PIP_DB='mysqlclient'
113elif [ $DATABASE_CHOICE == 'postgres' ]; then
114 DATABASE_CONFIG="
115 'default': {
116 'ENGINE': 'django.db.backends.postgresql_psycopg2',
117 'NAME': '${DB_NAME}',
118 'USER': '${DB_USER}',
119 'PASSWORD': '${PASSWORD}',
120 'HOST': 'localhost',
121 'PORT': '',
122 },
123 "
124 PIP_DB='psycopg2'
125fi
126echo "### Django settings generated by deploy.sh ###
127$APP_SETTINGS
128DEBUG = False
129SECRET_KEY = '$(openssl rand -base64 42)'
130SERVER_NAME = '$(hostname -A)'.strip()
131DATABASES = {$DATABASE_CONFIG}
132" | tee "${SOURCE_DIR}/${DJANGO_PROJECT_DIR}/${DJANGO_APP_DIR}/production_settings.py" 1> /dev/null
133unset PASSWORD
134
135# Move project files
136$SUDO mv "${SOURCE_DIR}/${DJANGO_PROJECT_DIR}" "${DEPLOY_PATH}/${DJANGO_PROJECT_DIR}"
137$SUDO chown -R "${SERVICE_USER_NAME}:${SERVER_USER}" "${DEPLOY_PATH}/${DJANGO_PROJECT_DIR}"
138echo -e $DONE
139
140# Create Python virtualenv and install dependencies
141echo -n "Setting up Python environment..."
142VENV="${DEPLOY_PATH}/${DJANGO_PROJECT_DIR}/.venv"
143$SUDO python3 -m venv $VENV
144source $VENV/bin/activate
145$SUDO $VENV/bin/pip install --upgrade pip 1> /dev/null
146$SUDO $VENV/bin/pip install -r "${SOURCE_DIR}/requirements.txt" 1> /dev/null
147$SUDO $VENV/bin/pip install gunicorn $PIP_DB 1> /dev/null
148$SUDO $VENV/bin/python "${DEPLOY_PATH}/${DJANGO_PROJECT_DIR}/manage.py" makemigrations 1> /dev/null
149$SUDO $VENV/bin/python "${DEPLOY_PATH}/${DJANGO_PROJECT_DIR}/manage.py" migrate
150echo -e $DONE
151
152# Create Systemd unit files
153echo -n "Configuring gunicorn systemd service..."
154echo "### Systemd service config generated by deploy.sh ###
155[Unit]
156Description=gunicorn daemon for ${APPNAME}
157Requires=${SYSTEMD_NAME}.socket
158After=network.target
159
160[Service]
161User=${SERVICE_USER_NAME}
162Group=${SERVER_USER}
163WorkingDirectory=${DEPLOY_PATH}/${DJANGO_PROJECT_DIR}
164ExecStart=${VENV}/bin/gunicorn \\
165 --workers ${WORKERS} \\
166 --bind unix:/var/run/${GUNICORN_SOCKET} \\
167 ${APPNAME}.wsgi:application
168
169[Install]
170WantedBy=multi-user.target
171" | $SUDO tee "/etc/systemd/system/${SYSTEMD_NAME}.service" 1> /dev/null
172echo "### Systemd socket config generated by deploy.sh ###
173[Unit]
174Description=gunicorn socket for ${APPNAME}
175
176[Socket]
177ListenStream=/var/run/${GUNICORN_SOCKET}
178
179[Install]
180WantedBy=sockets.target
181" | $SUDO tee "/etc/systemd/system/${SYSTEMD_NAME}.socket" 1> /dev/null
182$SUDO systemctl enable --now $SYSTEMD_NAME.socket &> /dev/null
183$SUDO systemctl enable --now $SYSTEMD_NAME.service &> /dev/null
184echo -e $DONE
185
186# Generate certificate
187echo -n "Generating certificate..."
188PKI="/etc/pki/nginx"
189$SUDO mkdir -p "${PKI}/private"
190$SUDO openssl req \
191 -new \
192 -newkey rsa:4096 \
193 -days 3650 \
194 -nodes \
195 -x509 \
196 -subj "/C=CC/ST=State/L=City/O=Org/CN=$(hostname -A)" \
197 -keyout "${PKI}/private/${APPNAME}.key" \
198 -out "$PKI/${APPNAME}.crt" &> /dev/null
199echo -e $DONE
200
201# Generate Diffie Hellman parameters
202echo -n "Generating DH params..."
203$SUDO openssl dhparam -out /etc/nginx/dhparam.pem 4096 &> /dev/null
204echo -e $DONE
205
206# Configure Nginx
207echo -n "Configuring Nginx..."
208# Disable builtin site and/or sites-enabled nonsense
209LINE_NUM=$(awk '/include \/etc\/nginx\/conf.d/{ print NR+1; exit }' /etc/nginx/nginx.conf)
210$SUDO sed -i "${LINE_NUM},$ d" /etc/nginx/nginx.conf &> /dev/null
211echo "}" | $SUDO tee --append /etc/nginx/nginx.conf 1> /dev/null
212# Add new config
213echo "### Nginx config generated by deploy.sh ###
214server {
215 listen ${SERVER_PORT} ssl http2 default_server;
216 listen [::]:${SERVER_PORT} ssl http2 default_server;
217 server_name ${NGINX_SERVER_NAME};
218 root /usr/share/nginx/html;
219
220 server_tokens off;
221
222 client_body_timeout 10;
223 client_header_timeout 10;
224 keepalive_timeout 5 5;
225 send_timeout 10;
226
227 ssl_certificate '${PKI}/${APPNAME}.crt';
228 ssl_certificate_key '${PKI}/private/${APPNAME}.key';
229 ssl_session_cache shared:SSL:10m;
230 ssl_session_timeout 10m;
231 ssl_protocols TLSv1.2 TLSv1.3;
232 ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
233 ssl_dhparam /etc/nginx/dhparam.pem;
234 ssl_prefer_server_ciphers on;
235
236 add_header X-Frame-Options SAMEORIGIN;
237 add_header X-XSS-Protection '1; mode=block';
238
239 # Load configuration files for the default server block.
240 include /etc/nginx/default.d/*.conf;
241
242 location /${ONLINE_PATH}static/ {
243 root ${DEPLOY_PATH}/${DJANGO_PROJECT_DIR};
244 }
245
246 location /${ONLINE_PATH} {
247 proxy_redirect off;
248 proxy_set_header Host \$http_host;
249 proxy_set_header X-Real-IP \$remote_addr;
250 proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
251 proxy_set_header X-Forwarded-Proto \$scheme;
252 proxy_pass http://unix:/var/run/${GUNICORN_SOCKET};
253 proxy_connect_timeout 30s;
254 proxy_read_timeout 30s;
255 access_log /var/log/nginx/${NGINX_SERVER_NAME}-access.log;
256 error_log /var/log/nginx/${NGINX_SERVER_NAME}-error.log;
257 }
258}
259" | $SUDO tee "/etc/nginx/conf.d/${NGINX_SERVER_NAME}.conf" 1> /dev/null
260echo -e $DONE
261
262# Check if SELinux present, if so correct contexts and permissions
263if [ "$(cat /etc/sysconfig/selinux 2> /dev/null)" ]; then
264 echo -n "Adjusting SELinux contexts..."
265 $SUDO semanage fcontext -at httpd_sys_content_t "${DEPLOY_PATH}/${DJANGO_PROJECT_DIR}(/.*)?"
266 $SUDO semanage fcontext -at httpd_config_t "/etc/nginx/conf.d/${NGINX_SERVER_NAME}.conf"
267 $SUDO semanage fcontext -at httpd_var_run_t "/var/run/${GUNICORN_SOCKET}"
268 $SUDO restorecon -R "${DEPLOY_PATH}/${DJANGO_PROJECT_DIR}"
269 $SUDO restorecon "/etc/nginx/conf.d/${NGINX_SERVER_NAME}.conf"
270 $SUDO restorecon "/var/run/${GUNICORN_SOCKET}"
271 echo "
272 module ${APPNAME} 1.0;
273
274 require {
275 type httpd_t;
276 type init_t;
277 class unix_stream_socket connectto;
278 }
279
280 allow httpd_t init_t:unix_stream_socket connectto;
281 " | $SUDO tee "${SOURCE_DIR}/${APPNAME}.te" 1> /dev/null
282 $SUDO checkmodule -M -m -o "${SOURCE_DIR}/${APPNAME}.mod" "${SOURCE_DIR}/${APPNAME}.te" 1> /dev/null
283 $SUDO semodule_package -o "${SOURCE_DIR}/${APPNAME}.pp" -m "${SOURCE_DIR}/${APPNAME}.mod"
284 $SUDO semodule -i "${SOURCE_DIR}/${APPNAME}.pp"
285 $SUDO rm "${SOURCE_DIR}/${APPNAME}.pp" "${SOURCE_DIR}/${APPNAME}.mod" "${SOURCE_DIR}/${APPNAME}.te"
286 echo -e $DONE
287fi
288
289# Enabled and start Nginx
290echo -n "Starting web server..."
291$SUDO systemctl enable --now nginx &> /dev/null
292# For some reason debian systems are difficult about this
293sleep 5
294$SUDO systemctl restart nginx
295echo -e $DONE
296
297# Delete packages that are no longer needed
298echo "The following system packages will be removed: $EXTRA_SYSTEM_PACKAGES"
299echo -n "Cleaning up system packages..."
300$SUDO $PKGMGR $PKGDEL -y $EXTRA_SYSTEM_PACKAGES &> /dev/null
301echo -e $DONE
302
303# All done! Take a nap!
304echo -e "${GREEN}Deploy finished!${NOCOLOR}"
305