2 # Copyright (C) 2016 Ian Kelling
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 [[ $EUID == 0 ]] ||
exec sudo
-E "$BASH_SOURCE" "$@"
19 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
21 shopt -s nullglob
# used in apache config file expansion
25 Usage: ${0##*/} [OPTIONS] [EXTRA_SETTINGS_FILE] apache2|nginx DOMAIN
26 apache/nginx config & let's encrypt
28 If using tls then it expects certbot to be installed and in PATH.
31 EXTRA_SETTINGS_FILE can be - for stdin
32 -e EMAIL Contact address for let's encrypt. Default is
33 root@\$(hostname -A|awk '{print $1}')
34 which is root@$(hostname -A|awk '{print $1}') on this host.
35 -f [ADDR:]PORT Enable proxy to [ADDR:]PORT. ADDR default is 127.0.0.1
36 -i Insecure, no ssl. Not implemented for nginx.
37 -p PORT Main port to listen on, default 443. 80 implies -i.
39 -h|--help Print help and exit
41 Note: Uses GNU getopt options parsing style
46 ##### begin command line parsing ########
51 temp
=$
(getopt
-l help e
:i
:f
:p
:r
:h
"$@") || usage
1
55 -e) email
="$2"; shift 2 ;;
56 -f) proxy
="$2"; shift 2 ;;
57 -i) ssl
=false
; shift ;;
58 -p) port
="$2"; shift 2 ;;
59 -r) root
="$2"; shift 2 ;;
62 *) echo "$0: Internal error!" ; exit 1 ;;
66 if (( ${#@} == 3 )); then
67 read -r extra_settings t h
<<<"${@}"
74 *) echo "$0: error: expected apache2 or nginx arg"; usage
1 ;;
78 echo "$0: error: expected domain and type arg"
82 if [[ ! $root ]]; then
87 [[ $proxy == *:* ]] || proxy
=127.0.0.1:$proxy
90 if [[ ! $email ]]; then
91 email
=root@$
(hostname
-A|
awk '{print $1}')
95 ##### end command line parsing ########
97 se
=/etc
/$t/sites-enabled
98 cert_dir
=/etc
/letsencrypt
/live
/$h
101 vhost_file
=$se/$h.conf
102 redir_file
=$se/$h-redir.conf
104 if [[ $port == 80 ]]; then
106 # remove any thats hanging around
112 f
=$cert_dir/fullchain.pem
113 if [[ ! -e $f ]] || openssl x509
-checkend 86400 -noout -in $f; then
115 # adds every security option
116 certbot certonly
-n --hsts --staple-ocsp --uir --must-staple --email $email --staple-ocsp --no-self-upgrade --agree-tos --apache -d $h
122 if [[ $t == apache2
]]; then
123 rm -f $se/000-default.conf
124 # note, we exepct ServerRoot of /etc/apache2
125 # apache requires exactly 1 listen directive per port (when no ip is also given),
126 # so we have to parse the config to do it programatically.
130 conf_files
=(apache2.conf
)
133 for (( i
=0; i
< ${#conf_files[@]}; i
++ )); do
135 # note: globs are expanded here.
136 conf_files
+=( $
(sed -rn "s,^\s*Include(Optional)?\s+(\S+).*,\2,p" "$f") )
137 case $
(readlink
-f "$f") in
138 $vhost_file|
$redir_file) continue ;;
141 for p
in $
(sed -rn "s,^\s*listen\s+(\S+).*,\1,Ip" "$f"); do
143 80) listen_80
=true
;;&
144 $port) listen_port
=true
;;
150 cat >$vhost_file <<EOF
151 <VirtualHost *:$port>
157 if [[ $extra_settings ]]; then
158 cat -- $extra_settings >>$vhost_file
162 if [[ -e /etc
/apache
2/mods-available
/http2.load
]]; then
163 # https://httpd.apache.org/docs/2.4/mod/mod_http2.html
165 cat >>$vhost_file <<EOF
166 Protocols h2 http/1.1
170 if [[ $proxy ]]; then
171 a2enmod proxy proxy_http
172 # fyi: trailing slash is important
173 # reference: https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html
174 cat >>$vhost_file <<EOF
175 ProxyPass "/" "http://$proxy/"
176 ProxyPassReverse "/" "http://$proxy/"
184 common_ssl_conf
=/etc
/apache
2/common-ssl.conf
185 cat >>$vhost_file <<EOF
186 SSLCertificateFile $cert_dir/fullchain.pem
187 SSLCertificateKeyFile $cert_dir/privkey.pem
188 Include $common_ssl_conf
189 # From cerbot generated config example, taken 4/2017,
190 # should be rechecked once a year or so.
191 Header always set Strict-Transport-Security "max-age=31536000"
193 Header always set Content-Security-Policy upgrade-insecure-requests
196 cat >/etc
/apache
2/conf-enabled
/local-custom.conf
<<'EOF'
197 # vhost_combined with %D (request time in microseconds)
198 # this file is just a convenient place to drop it.
199 LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %D" vhost_time_combined
200 SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
203 echo "$0: creating $redir_file"
204 cat >$redir_file <<EOF
207 ServerAdmin webmaster@localhost
208 DocumentRoot /var/www/html
210 ErrorLog \${APACHE_LOG_DIR}/error.log
211 CustomLog \${APACHE_LOG_DIR}/access.log vhost_time_combined
214 RewriteCond %{SERVER_NAME} =$h
215 RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]
218 if ! $listen_80; then
219 cat >>$redir_file <<'EOF'
224 # this is a copy of a file certbot, see below.
225 echo "$0: creating $common_ssl_conf"
226 cat >$common_ssl_conf <<'EOF'
227 # Baseline setting to Include for SSL sites
231 # Intermediate configuration, tweak to your needs
232 SSLProtocol all -SSLv2 -SSLv3
233 SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
234 SSLHonorCipherOrder on
237 SSLOptions +StrictRequire
239 # Add vhost name to log entries:
240 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
241 LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
243 #CustomLog /var/log/apache2/access.log vhost_combined
245 #ErrorLog /var/log/apache2/error.log
247 # Always ensure Cookies have "Secure" set (JAH 2012/1)
248 #Header edit Set-Cookie (?i)^(.*)(;\s*secure)??((\s*;)?(.*)) "$1; Secure$3$4"
251 upstream
=https
://github.com
/certbot
/certbot
/raw
/master
/certbot-apache
/certbot_apache
/options-ssl-apache.conf
252 if ! diff -c <(wget
-q -O - $upstream) $common_ssl_conf; then
259 upstream ssl settings differ from the snapshot we have taken!!!
260 We diffed with this command:
261 diff -c <(wget -q -O - $upstream) $common_ssl_conf
262 Update this script to take care this warning!!!!!
268 cat >>$vhost_file <<'EOF'
269 ErrorLog ${APACHE_LOG_DIR}/error.log
270 CustomLog ${APACHE_LOG_DIR}/access.log vhost_time_combined
274 if ! $listen_port; then
275 # reference: https://httpd.apache.org/docs/2.4/mod/mpm_common.html#listen
276 cat >>$vhost_file <<EOF
277 listen ${port}${https_arg}
282 a2enmod ssl rewrite
# rewrite needed for httpredir
283 service apache2 restart
285 # I rarely look at how much traffic I get, so let's keep that info
286 # around for longer than the default of 2 weeks.
287 sed -ri --follow-symlinks 's/^(\s*rotate\s).*/\1 365/' /etc
/logrotate.d
/apache2
288 fi ###### end if apache
290 if [[ $t == nginx
]]; then
291 common_ssl_conf
=/etc
/nginx
/common-ssl.conf
295 [[ -e dh2048.pem
]] || openssl dhparam
-out dh2048.pem
2048
297 if nginx
-V |
& grep -- '--with-http_v2_module\b' &>/dev
/null
; then
301 cat >$common_ssl_conf <<'EOF'
302 # let's encrypt gives us a bad nginx config, so use this:
303 # https://mozilla.github.io/server-side-tls/ssl-config-generator/
304 # using modern config. last checked 2017/4/22
305 ssl_session_timeout 1d;
306 ssl_session_cache shared:SSL:50m;
307 ssl_session_tickets off;
309 # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
310 ssl_dhparam /etc/nginx/dh2048.pem;
312 # modern configuration. tweak to your needs.
313 ssl_protocols TLSv1.2;
314 ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
315 ssl_prefer_server_ciphers on;
317 # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
318 add_header Strict-Transport-Security max-age=15768000;
321 # fetch OCSP records from URL in ssl_certificate and cache them
323 ssl_stapling_verify on;
325 ## verify chain of trust of OCSP response using Root CA and Intermediate certs
326 # ian: commented out, unnecessary for le certs or my nginx ver.
327 #ssl_trusted_certificate $cert_dir/fullchain.pem;;
329 # ian: commented out, our local dns is expected to work fine.
330 #resolver <IP DNS resolver>;
332 cat >$vhost_file <<EOF
334 server_name $h www.$h;
336 listen $port ssl $http2_arg;
337 listen [::]:$port ssl $http2_arg;
339 # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
340 ssl_certificate $cert_dir/fullchain.pem;
341 ssl_certificate_key $cert_dir/privkey.pem;
342 include $common_ssl_conf;
344 if [[ $extra_settings ]]; then
345 cat $extra_settings >>$vhost_file
348 if [[ $proxy ]]; then
349 cat >>$vhost_file <<EOF
351 proxy_set_header Host \$host;
352 proxy_set_header X-Real-IP \$remote_addr;
353 proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
354 proxy_set_header X-Forwarded-Ssl on;
355 proxy_set_header X-Forwarded-Port $port;
356 proxy_pass http://$proxy;
361 cat >>$vhost_file <<EOF
365 cat >$redir_file <<EOF
367 server_name $h www.$h;
368 listen 80 $http2_arg;
369 listen [::]:80 $http2_arg;
370 return 301 https://$server_name$request_uri;
374 service nginx restart
376 fi ####### end if nginx