3 # Script to deploy certificates to remote server by SSH
4 # Note that SSH must be able to login to remote host without a password...
5 # SSH Keys must have been exchanged with the remote host. Validate and
6 # test that you can login to USER@SERVER from the host running acme.sh before
9 # The following variables exported from environment will be used.
10 # If not set then values previously saved in domain.conf file are used.
12 # Only a username is required. All others are optional.
14 # The following examples are for QNAP NAS running QTS 4.2
15 # export DEPLOY_SSH_CMD="" # defaults to "ssh -T"
16 # export DEPLOY_SSH_USER="admin" # required
17 # export DEPLOY_SSH_SERVER="qnap" # defaults to domain name
18 # export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem"
19 # export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem"
20 # export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem"
21 # export DEPLOY_SSH_FULLCHAIN=""
22 # export DEPLOY_SSH_REMOTE_CMD="/etc/init.d/stunnel.sh restart"
23 # export DEPLOY_SSH_BACKUP="" # yes or no, default to yes or previously saved value
24 # export DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy" # path on remote system. Defaults to .acme_ssh_deploy
25 # export DEPLOY_SSH_MULTI_CALL="" # yes or no, default to no or previously saved value
27 ######## Public functions #####################
29 #domain keyfile certfile cafile fullchain
36 _deploy_ssh_servers
=""
38 _debug _cdomain
"$_cdomain"
40 _debug _ccert
"$_ccert"
42 _debug _cfullchain
"$_cfullchain"
44 # USER is required to login by SSH to remote host.
45 _getdeployconf DEPLOY_SSH_USER
46 _debug2 DEPLOY_SSH_USER
"$DEPLOY_SSH_USER"
47 if [ -z "$DEPLOY_SSH_USER" ]; then
48 if [ -z "$Le_Deploy_ssh_user" ]; then
49 _err
"DEPLOY_SSH_USER not defined."
53 Le_Deploy_ssh_user
="$DEPLOY_SSH_USER"
54 _savedomainconf Le_Deploy_ssh_user
"$Le_Deploy_ssh_user"
57 # SERVER is optional. If not provided then use _cdomain
58 _getdeployconf DEPLOY_SSH_SERVER
59 _debug2 DEPLOY_SSH_SERVER
"$DEPLOY_SSH_SERVER"
60 if [ -n "$DEPLOY_SSH_SERVER" ]; then
61 Le_Deploy_ssh_server
="$DEPLOY_SSH_SERVER"
62 _savedomainconf Le_Deploy_ssh_server
"$Le_Deploy_ssh_server"
63 elif [ -z "$Le_Deploy_ssh_server" ]; then
64 Le_Deploy_ssh_server
="$_cdomain"
67 # CMD is optional. If not provided then use ssh
68 _getdeployconf DEPLOY_SSH_CMD
69 _debug2 DEPLOY_SSH_CMD
"$DEPLOY_SSH_CMD"
70 if [ -n "$DEPLOY_SSH_CMD" ]; then
71 Le_Deploy_ssh_cmd
="$DEPLOY_SSH_CMD"
72 _savedomainconf Le_Deploy_ssh_cmd
"$Le_Deploy_ssh_cmd"
73 elif [ -z "$Le_Deploy_ssh_cmd" ]; then
74 Le_Deploy_ssh_cmd
="ssh -T"
77 # BACKUP is optional. If not provided then default to previously saved value or yes.
78 _getdeployconf DEPLOY_SSH_BACKUP
79 _debug2 DEPLOY_SSH_BACKUP
"$DEPLOY_SSH_BACKUP"
80 if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
81 Le_Deploy_ssh_backup
="no"
82 elif [ -z "$Le_Deploy_ssh_backup" ] ||
[ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
83 Le_Deploy_ssh_backup
="yes"
85 _savedomainconf Le_Deploy_ssh_backup
"$Le_Deploy_ssh_backup"
87 # BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
88 _getdeployconf DEPLOY_SSH_BACKUP_PATH
89 _debug2 DEPLOY_SSH_BACKUP_PATH
"$DEPLOY_SSH_BACKUP_PATH"
90 if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
91 Le_Deploy_ssh_backup_path
="$DEPLOY_SSH_BACKUP_PATH"
92 elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
93 Le_Deploy_ssh_backup_path
=".acme_ssh_deploy"
95 _savedomainconf Le_Deploy_ssh_backup_path
"$Le_Deploy_ssh_backup_path"
97 # MULTI_CALL is optional. If not provided then default to previously saved
98 # value (which may be undefined... equivalent to "no").
99 _getdeployconf DEPLOY_SSH_MULTI_CALL
100 _debug2 DEPLOY_SSH_MULTI_CALL
"$DEPLOY_SSH_MULTI_CALL"
101 if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
102 Le_Deploy_ssh_multi_call
="yes"
103 _savedomainconf Le_Deploy_ssh_multi_call
"$Le_Deploy_ssh_multi_call"
104 elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then
105 Le_Deploy_ssh_multi_call
=""
106 _cleardomainconf Le_Deploy_ssh_multi_call
109 _deploy_ssh_servers
=$Le_Deploy_ssh_server
110 for Le_Deploy_ssh_server
in $_deploy_ssh_servers; do
121 _info
"Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
122 if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
123 _info
"Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
125 _info
"Required commands batched and sent in single call to remote host"
128 if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
129 _backupprefix
="$Le_Deploy_ssh_backup_path/$_cdomain-backup"
130 _backupdir
="$_backupprefix-$(_utc_date | tr ' ' '-')"
131 # run cleanup on the backup directory, erase all older
132 # than 180 days (15552000 seconds).
133 _cmdstr
="{ now=\"\$(date -u +%s)\"; for fn in $_backupprefix*; \
134 do if [ -d \"\$fn\" ] && [ \"\$(expr \$now - \$(date -ur \$fn +%s) )\" -ge \"15552000\" ]; \
135 then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; done; }; $_cmdstr"
136 # Alternate version of above... _cmdstr="find $_backupprefix* -type d -mtime +180 2>/dev/null | xargs rm -rf; $_cmdstr"
137 # Create our backup directory for overwritten cert files.
138 _cmdstr
="mkdir -p $_backupdir; $_cmdstr"
139 _info
"Backup of old certificate files will be placed in remote directory $_backupdir"
140 _info
"Backup directories erased after 180 days."
141 if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
142 if ! _ssh_remote_cmd
"$_cmdstr"; then
149 # KEYFILE is optional.
150 # If provided then private key will be copied to provided filename.
151 _getdeployconf DEPLOY_SSH_KEYFILE
152 _debug2 DEPLOY_SSH_KEYFILE
"$DEPLOY_SSH_KEYFILE"
153 if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
154 Le_Deploy_ssh_keyfile
="$DEPLOY_SSH_KEYFILE"
155 _savedomainconf Le_Deploy_ssh_keyfile
"$Le_Deploy_ssh_keyfile"
157 if [ -n "$Le_Deploy_ssh_keyfile" ]; then
158 if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
159 # backup file we are about to overwrite.
160 _cmdstr
="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;"
162 # copy new certificate into file.
163 _cmdstr
="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;"
164 _info
"will copy private key to remote file $Le_Deploy_ssh_keyfile"
165 if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
166 if ! _ssh_remote_cmd
"$_cmdstr"; then
173 # CERTFILE is optional.
174 # If provided then certificate will be copied or appended to provided filename.
175 _getdeployconf DEPLOY_SSH_CERTFILE
176 _debug2 DEPLOY_SSH_CERTFILE
"$DEPLOY_SSH_CERTFILE"
177 if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
178 Le_Deploy_ssh_certfile
="$DEPLOY_SSH_CERTFILE"
179 _savedomainconf Le_Deploy_ssh_certfile
"$Le_Deploy_ssh_certfile"
181 if [ -n "$Le_Deploy_ssh_certfile" ]; then
183 if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then
184 # if filename is same as previous file then append.
186 elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
187 # backup file we are about to overwrite.
188 _cmdstr
="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;"
190 # copy new certificate into file.
191 _cmdstr
="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;"
192 _info
"will copy certificate to remote file $Le_Deploy_ssh_certfile"
193 if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
194 if ! _ssh_remote_cmd
"$_cmdstr"; then
201 # CAFILE is optional.
202 # If provided then CA intermediate certificate will be copied or appended to provided filename.
203 _getdeployconf DEPLOY_SSH_CAFILE
204 _debug2 DEPLOY_SSH_CAFILE
"$DEPLOY_SSH_CAFILE"
205 if [ -n "$DEPLOY_SSH_CAFILE" ]; then
206 Le_Deploy_ssh_cafile
="$DEPLOY_SSH_CAFILE"
207 _savedomainconf Le_Deploy_ssh_cafile
"$Le_Deploy_ssh_cafile"
209 if [ -n "$Le_Deploy_ssh_cafile" ]; then
211 if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] ||
212 [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
213 # if filename is same as previous file then append.
215 elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
216 # backup file we are about to overwrite.
217 _cmdstr
="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;"
219 # copy new certificate into file.
220 _cmdstr
="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;"
221 _info
"will copy CA file to remote file $Le_Deploy_ssh_cafile"
222 if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
223 if ! _ssh_remote_cmd
"$_cmdstr"; then
230 # FULLCHAIN is optional.
231 # If provided then fullchain certificate will be copied or appended to provided filename.
232 _getdeployconf DEPLOY_SSH_FULLCHAIN
233 _debug2 DEPLOY_SSH_FULLCHAIN
"$DEPLOY_SSH_FULLCHAIN"
234 if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
235 Le_Deploy_ssh_fullchain
="$DEPLOY_SSH_FULLCHAIN"
236 _savedomainconf Le_Deploy_ssh_fullchain
"$Le_Deploy_ssh_fullchain"
238 if [ -n "$Le_Deploy_ssh_fullchain" ]; then
240 if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] ||
241 [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] ||
242 [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
243 # if filename is same as previous file then append.
245 elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
246 # backup file we are about to overwrite.
247 _cmdstr
="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;"
249 # copy new certificate into file.
250 _cmdstr
="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;"
251 _info
"will copy fullchain to remote file $Le_Deploy_ssh_fullchain"
252 if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
253 if ! _ssh_remote_cmd
"$_cmdstr"; then
260 # REMOTE_CMD is optional.
261 # If provided then this command will be executed on remote host.
262 _getdeployconf DEPLOY_SSH_REMOTE_CMD
263 _debug2 DEPLOY_SSH_REMOTE_CMD
"$DEPLOY_SSH_REMOTE_CMD"
264 if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
265 Le_Deploy_ssh_remote_cmd
="$DEPLOY_SSH_REMOTE_CMD"
266 _savedomainconf Le_Deploy_ssh_remote_cmd
"$Le_Deploy_ssh_remote_cmd"
268 if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then
269 _cmdstr
="$_cmdstr $Le_Deploy_ssh_remote_cmd;"
270 _info
"Will execute remote command $Le_Deploy_ssh_remote_cmd"
271 if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
272 if ! _ssh_remote_cmd
"$_cmdstr"; then
279 # if commands not all sent in multiple calls then all commands sent in a single SSH call now...
280 if [ -n "$_cmdstr" ]; then
281 if ! _ssh_remote_cmd
"$_cmdstr"; then
291 _secure_debug
"Remote commands to execute: $_cmd"
292 _info
"Submitting sequence of commands to remote server by ssh"
293 # quotations in bash cmd below intended. Squash travis spellcheck error
294 # shellcheck disable=SC2029
295 $Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh
-c "'$_cmd'"
298 if [ "$_err_code" != "0" ]; then
299 _err
"Error code $_err_code returned from ssh"