├── lcget-sh ├── .github └── FUNDING.yml ├── ChangeLog ├── install.sh ├── lcget └── README.md /lcget-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | expect lcget ${1+"$@"} 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: neurobin 2 | liberapay: neurobin 3 | ko_fi: neurobin 4 | issuehunt: neurobin 5 | open_collective: neurobin 6 | otechie: neurobin 7 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | #ChangeLog: 2 | 3 | ###`0.0.3`: Mon Jun 6 14:08:03 UTC 2016 4 | Changed directory based challenge completion to file based method 5 | 6 | ###`0.0.1`: Sat Jan 16 14:40:52 UTC 2016 7 | 8 | **Happy birth day** 9 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ##We will install to home directory. no need for root privilege 4 | #if [ $EUID -ne 0 ]; then 5 | # echo -e "\n*********This script must be run with root privilege*********" 6 | # echo -e "*******************Sorry! Exiting*************************\n" 7 | # exit 1 8 | #fi 9 | 10 | var=$HOME/bin 11 | 12 | mkdir -p $HOME/bin && 13 | chmod 755 lcget && 14 | cp lcget $HOME/bin && 15 | #Adding $HOME/bin to environment variable 16 | if ! echo $PATH | grep -q ":$var\([/:]\|$\)"; then echo "export PATH=\$PATH:$var" >> ~/.bashrc && . ~/.bashrc ;fi 17 | echo "lcget installed." || { 18 | echo "Failed to install. Abort."; exit 1; } 19 | 20 | echo "Installing dependencies..." 21 | 22 | #Install jssh (required by lcget) 23 | if [ ! -f $HOME/bin/jssh ];then 24 | echo "Installing jssh (ssh wrapper)" 25 | if git clone https://github.com/neurobin/jssh;then 26 | cd jssh && 27 | chmod 755 jssh && 28 | cp jssh $HOME/bin && 29 | echo "Installed jssh successfully." || { 30 | echo "Failed to install jssh. Abort."; exit 1; } 31 | elif wget https://github.com/neurobin/jssh/release.tar.gz;then 32 | #try with wget 33 | tar -xvf jssh-release.tar.gz && 34 | cd jssh-release && 35 | chmod 755 jssh && 36 | cp jssh $HOME/bin && 37 | echo "Installed jssh successfully." || { 38 | echo "Failed to install jssh. Abort."; exit 1; } 39 | else 40 | echo " 41 | Failed to install jssh. Install it by downloading from 42 | https://github.com/neurobin/jssh 43 | To install, just copy the jssh file to $HOME/bin 44 | and give it execution (755 recommended) permission" 45 | fi 46 | fi 47 | echo " 48 | done. 49 | ***$HOME/bin was added to PATH environment variable.*** 50 | To populate it run: 51 | . ~/.bashrc #don't forget the dot (.) 52 | If ~/.bashrc is not respected, then manually add the $HOME/bin 53 | to PATH environment variable." 54 | 55 | -------------------------------------------------------------------------------- /lcget: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -- 2 | 3 | ##################################################################### 4 | # Coding conventions: 5 | # * Error message must start with 'E: ' (and end with 'Abort.' if it 6 | # needs to be aborted). 7 | # 8 | ##################################################################### 9 | 10 | set p_name "lcget" 11 | set p_author "Md. Jahidul Hamid" 12 | set p_author_eu "jahidulhamid" 13 | set p_author_ed "yahoo.com" 14 | set p_version "0.0.3" 15 | set p_source "https://github.com/neurobin/lcget" 16 | set p_bugt "$p_source/issues" 17 | set jssh_link "https://github.com/neurobin/jssh" 18 | 19 | set help " 20 | ##################################################################### 21 | # Let's Encrypt wrapper to automate the process of completing 22 | # challenges to get free SSL certificates from Let's Encrypt. 23 | # ################################################################### 24 | # Takes same kind of arguments as the letsencrypt command 25 | # and depends on letsencrypt to run those commands and finally 26 | # Get the certificates. All this script does is to complete the 27 | # challenges using ssh login to remote server. 28 | # 29 | # Usage: 30 | # $p_name \[native and/or letsencrypt options/args] 31 | # 32 | # Native options: 33 | # 34 | # -lp /path/to/letsencrypt/launcher : If this option is not given 35 | # It will assume 'letsencrypt' as the name of the launcher 36 | # and it resides in a path in PATH environment 37 | # variable in your system. 38 | # 39 | # -jp /path/to/jssh : If this option is not given it will be 40 | # assumed that jssh is in a path in PATH environment 41 | # variable in your system i.e 'jssh' command will be 42 | # used by default 43 | ##################################################################### 44 | " 45 | 46 | set verinfo " 47 | Name: $p_name 48 | Version: $p_version 49 | Source: $p_source 50 | Bug report: $p_bugt 51 | Author: $p_author 52 | 53 | Author email: 54 | username: $p_author_eu 55 | domain: $p_author_ed 56 | " 57 | 58 | set err_api_change " 59 | It seems Let's Encrypt api has gone through some changes. 60 | Please update this script and if you get this error again, 61 | then please file a bug report at $p_bugt 62 | with all available outputs/logs. 63 | " 64 | 65 | 66 | ##################################################################### 67 | proc get_ssh_command_for_http_challenge {dom file_p cont} { 68 | if {$dom == ""} { 69 | puts "E: Couldn't parse domain. Abort." 70 | exit 1 71 | } 72 | if {$file_p == ""} { 73 | puts "E: Couldn't parse directory name. Abort." 74 | exit 1 75 | } 76 | if {$cont == ""} { 77 | puts "E: Couldn't parse content. Abort." 78 | exit 1 79 | } 80 | set cdir [file dirname $file_p] 81 | set comms "echo 'Completing challenge...' 82 | mkdir -p '$cdir' && echo 'Created dir : $cdir' 83 | if printf '%s' '$cont' > '$file_p'; then 84 | echo 'Created file: $file_p' 85 | else 86 | echo 'E: Failed to complete challenge for $dom. Abort.' 87 | exit 1 88 | fi" 89 | 90 | return "$comms" 91 | } 92 | 93 | ##################################################################### 94 | 95 | 96 | set timeout -1 97 | #exp_internal 1 98 | 99 | set program "letsencrypt" 100 | set ssh_prog "jssh" 101 | set arguments [lrange $argv 0 end] 102 | 103 | #Check for no-args 104 | if {[llength $argv] == 0} { 105 | puts " 106 | E: No args passed. 107 | Usage: $argv0 subcommand options 108 | Example: $argv0 certonly -c /path/to/config/file 109 | " 110 | exit 1 111 | } 112 | 113 | #$argv 0 can not be empty 114 | if {[lindex $arguments 0] == "" } { 115 | puts " 116 | E: Empty argument. 117 | Usage: $argv0 subcommand options 118 | Example: $argv0 certonly -c /path/to/config/file 119 | " 120 | exit 1 121 | } 122 | 123 | 124 | #Check for -lp option. Set the program path 125 | for {set var 0} {$var<$argc} {incr var} { 126 | if {[lindex $arguments $var] == "-lp" || [lindex $arguments $var] == "--launcher-path"} { 127 | if {[lindex $arguments [expr {$var+1}]] != ""} { 128 | set program [lindex $arguments [expr {$var+1}]] 129 | set arguments [lreplace $arguments $var [expr {$var+1}]] 130 | } else { 131 | puts "E: Argument missing for option: [lindex $arguments $var]" 132 | exit 1 133 | } 134 | } 135 | if {[lindex $arguments $var] == "-jp" || [lindex $arguments $var] == "--jssh-path"} { 136 | if {[lindex $arguments [expr {$var+1}]] != ""} { 137 | set ssh_prog [lindex $arguments [expr {$var+1}]] 138 | set arguments [lreplace $arguments $var [expr {$var+1}]] 139 | } else { 140 | puts "E: Argument missing for option: [lindex $arguments $var]" 141 | exit 1 142 | } 143 | } 144 | if {[lindex $arguments $var] == "-h" || [lindex $arguments $var] == "--help"} { 145 | puts "$help" 146 | } 147 | if {[lindex $arguments $var] == "--version"} { 148 | puts "$verinfo" 149 | } 150 | } 151 | 152 | if {[catch {spawn -noecho $program --text {*}$arguments}]} { 153 | puts "E: Let's Encrypt launcher not found: $program\nYou can specify letsencrypt path with -lp option." 154 | exit 1 155 | } 156 | 157 | set letse_spawn $spawn_id 158 | 159 | 160 | while {1} { 161 | expect { 162 | #set spawn_id $letse_spawn 163 | timeout { exp_send_user "\nE: Failed!!!. Timed out.\n"; exit 1} 164 | eof {break} 165 | -nocase "*http*.well-known*acme-challenge*http*server*configured*continue" { 166 | set output $expect_out(buffer) 167 | set found [regexp {^.*(https?://)([^/]*)/([^[:space:]]*)[^:]*:[[:space:]]*([^[:space:]]*)} $output match protocol domain file_p cont] 168 | if {$found} { 169 | puts "\n\nProtocol: $protocol\nDomain: $domain\nFile: $file_p\nContent: $cont\n" 170 | } else { 171 | puts "\n\nCouldn't get challenge info.$err_api_change\n" 172 | exit 1 173 | } 174 | exp_send_user "Trying to complete challenge for $domain\n\n" 175 | set comms [get_ssh_command_for_http_challenge $domain $file_p $cont] 176 | 177 | set timeout 900 178 | if {[catch {spawn -noecho $ssh_prog -cdw $domain $comms}]} { 179 | puts "E: $ssh_prog command not found.\nIs jssh installed? If not then install it from $jssh_link\nOr if it exists then try giving the path with -jp option." 180 | exit 1 181 | } 182 | 183 | set jssh_spawn $spawn_id 184 | 185 | while {1} { 186 | expect { 187 | timeout { exp_send_user "\nE: Failed!!!. Timed out.\n"; exit 1} 188 | eof {break} 189 | -re "^.\{8,\}$" {#Should be at least 6 in regards of 'ssh: ' for catching unknown prompts 190 | set jssh_output $expect_out(buffer) 191 | #puts $jssh_output 192 | if {[regexp {^.*password.*$} $jssh_output match]} { 193 | stty -echo 194 | exp_send_user -- "" 195 | expect_user -re "(.*)\n" 196 | #exp_send_user "\n" 197 | stty echo 198 | set password $expect_out(1,string) 199 | exp_send "$password\r" 200 | } elseif {[regexp {^E:.*Abort} $jssh_output match]} { 201 | exp_send_user "\nE: Failed to complete challenge for $domain\n" 202 | exit 1 203 | } elseif {[regexp {^.*continue connecting.*[:?][[:space:]]*$} $jssh_output match]} { 204 | exp_send "yes\r" 205 | } elseif {[regexp {^ssh: .*no.*$} $jssh_output match]} { 206 | exp_send_user "\nE: Failed to complete challenge for $domain\n" 207 | exit 1 208 | } elseif {[regexp {^.\{8,\}[:?][[:space:]]*$} $jssh_output match]} {#catching unknown prompts 209 | expect_user -re "(.*)\n" 210 | set password $expect_out(1,string) 211 | exp_send "$password\r" 212 | } 213 | } 214 | } 215 | } 216 | exp_send_user "\nDone for $domain\n" 217 | set timeout -1 218 | if {[catch {exp_close $jssh_spawn}]} { 219 | #spawn was already closed 220 | } 221 | set spawn_id $letse_spawn 222 | exp_send "\r" 223 | } 224 | -nocase "*password" { 225 | stty -echo 226 | exp_send_user -- "" 227 | expect_user -re "(.*)\n" 228 | #exp_send_user "\n" 229 | stty echo 230 | set password $expect_out(1,string) 231 | exp_send "$password\r" 232 | } 233 | -nocase "*terms of service*\n*:" { 234 | exp_send_user -- "" 235 | #expect_user -re "(.*)\n" 236 | #set password $expect_out(1,string) 237 | #exp_send "$password\r" 238 | exp_send "a\r" 239 | #sending a as the answer 240 | } 241 | -nocase "*are you ok with your ip being logged\?*:" { 242 | exp_send_user -- "" 243 | #expect_user -re "(.*)\n" 244 | #set password $expect_out(1,string) 245 | #exp_send "$password\r" 246 | exp_send "y\r" 247 | #sending y as the answer 248 | } 249 | -nocase "*--------------*\n*--------------*:*" { 250 | exp_send_user -- "" 251 | expect_user -re "(.*)\n" 252 | set password $expect_out(1,string) 253 | exp_send "$password\r" 254 | } 255 | -nocase "*--------------*\n*--------------*Press Enter to Continue" { 256 | exp_send_user -- "" 257 | expect_user -re "(.*)\n" 258 | set password $expect_out(1,string) 259 | exp_send "$password\r" 260 | } 261 | } 262 | } 263 | 264 | 265 | 266 | #Clearing step, Finally close the spawns 267 | 268 | #set spawn_id $letse_spawn 269 | if {[catch {exp_close}]} { 270 | #spawn was already closed 271 | } 272 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **lcget** is a wrapper (written in [Tcl/expect](https://en.wikipedia.org/wiki/Expect)) for letsencrypt which automates the task of completing challenges for remote server/domains from a local machine. It relieves you of the pain of running multiple commands in multiple terminals. Most of the time, a single command in a single terminal will be enough to get the certificate from Let's Encrypt. It doesn't require sudo access on remote host if the document root is in /home directory i.e for shared hosting. 2 | 3 | # Mechanism: 4 | **lcget** is an [expect](https://en.wikipedia.org/wiki/Expect) script which runs the letsencrypt command and monitor its' output. When the challenge appears on the output of `letsencrypt` command, the script parses necessary information about the challenge and tries to complete the challenge itself. 5 | 6 | To complete the http challenge in manual mode, **lcget** requires ssh access to the remote host i.e it runs ssh commands to the remote host to meet the necessary requirements for the acme challenge. 7 | 8 | Currently, only the **http challenge in manual mode** is supported. 9 | 10 | 11 | # Dependencies: 12 | The script depends on the following tools/scripts: 13 | 14 | 1. **letsencrypt (certbot):** The letsencrypt tool itself. 15 | 2. **expect:** You may need to install this first if not installed. 16 | 2. **ssh:** It is installed by default in most Unix based system. 17 | 3. **jssh:** It is a wrapper to automate ssh login and/or running ssh commands. 18 | 19 | **To install jssh, download the [jssh script](https://github.com/neurobin/jssh) and put it in a bin directory which is in the PATH environment variable (e.g */usr/bin*)**. The **lcget** script uses `jssh` command to execute it by default. You can run **jssh** from any arbitrary path too; in that case, use the the **lcget** option `-jp` to provide the jssh path. For example: 20 | ```sh 21 | lcget certonly --manual -d example.com -m mymail@example.com -jp /path/to/jssh 22 | ``` 23 | 24 | # Install: 25 | 26 | First you will need to give execution permission to the script. An octal `755` permission is recommended. 27 | 28 | * You can run the script with full path or with `./lcget` by `cd`ing into the directory where it resides. 29 | * You can just copy the script into a standard bin directory (e.g */usr/bin*). 30 | * Or you can run the *install.sh* script which tries to install it in *~/bin* along with **jssh**. 31 | 32 | ## Installing examples: 33 | 34 | *Installing in /usr/bin* : 35 | 36 | ```sh 37 | chmod 755 path/to/lcget 38 | sudo cp path/to/lcget /usr/bin 39 | ``` 40 | *Installing in ~/bin* : 41 | ```sh 42 | chmod 755 path/to/lcget 43 | cp path/to/lcget $HOME/bin 44 | # Now add $HOME/bin to PATH environment variable if not added already 45 | var=$HOME/bin 46 | if ! echo $PATH | grep -q ":$var\([/:]\|$\)"; then echo "export PATH=\$PATH:$var" >> ~/.bashrc && . ~/.bashrc ;fi 47 | ``` 48 | ## Note: 49 | **If the script isn't recognized as an executable by the system**, then you may try the `lcget-sh` script provided. Furthermore, you can change the path of `lcget` to the actual path inside the `lcget-sh` script: 50 | ```sh 51 | #!/bin/sh 52 | expect /actual/path/to/lcget ${1+"$@"} 53 | ``` 54 | and install `lcget-sh` instead of `lcget`. In this case, you will be using `lcget-sh` as the **lcget** command. 55 | 56 | **Or** you can try fixing the shebang line (`#!/usr/bin/expect --`) to the correct one for an expect script if it is supported (don't forget the `--` part though). 57 | 58 | # Usage: 59 | 60 | ``` 61 | lcget [native or letsencrypt options] 62 | ``` 63 | **native options:** These are the options parsed and recognized by lcget. These are: 64 | 65 | * **--launcher-path, -lp :** Launcher path. You can define the letsencrypt launcher path with this option. 66 | * **-jssh-path, -jp :** Arbitrary **jssh** path. If given **jssh** will be run with the full path specified. 67 | * **--help, -h :** This is a mixed option. It will print both **lcget** and **letsencrypt** help. 68 | * **--version:** This is a mixed option. It will print version info for both **lcget** and **letsencrypt**. 69 | 70 | **letsencrypt options:** These are the options recognized by letsencrypt. These options are same as the options supported by the letsencrypt launcher. 71 | 72 | 73 | # How to: 74 | We will need to prepare a **jssh** config file for each of the domains we want to get Let's Encrypt ssl certificate for. We will do this just once, after that we will be running the `lcget` command only. 75 | 76 | ## Create jssh config file: 77 | 78 | The config file must follow the naming convention: **domain.conf** e.g *example.com.conf* for example.com, *www.example.com.conf* for www.example.com etc... 79 | 80 | To create a **jssh config file** run `jssh -aw -c` in a terminal and fill out necessary information. For example: 81 | 82 | ``` 83 | ~$ jssh -aw -c 84 | 85 | Give an easy and memorable name to your config file, something like example.com. 86 | Later you will call jssh with this name to login to remote. 87 | 88 | Enter config file name (without .conf): 89 | example.com 90 | Overwrite (y/n)?: 91 | y 92 | Enter domain/IP: 93 | example.com 94 | Enter port number: 95 | 22 96 | Enter username: 97 | neurobin 98 | 99 | If a working directory is specified, jssh -cdw example.com 100 | will run cd WorkDir just after logging in. 101 | 102 | Enter working directory: 103 | $HOME/public_html 104 | 105 | Saved as: /home/user/.neurobin/jssh/example.com.conf 106 | You will call jssh for this configuration like this: 107 | jssh example.com other_ssh_options_or_args 108 | 'jssh example.com' is the native jssh part. All other arguments 109 | will be forwarded to ssh command. Any jssh native option 110 | must be passed before example.com. 111 | You can edit the config file to make further changes. 112 | 113 | 114 | Additional: /home/user/.neurobin/jssh/www.example.com.conf 115 | ``` 116 | This will create a config file for *example.com* and also for `www.example.com` with the same configuration ( because of the `-aw` flag passed with jssh). 117 | 118 | **You must give the document root of your domain as the working directory.** 119 | 120 | As *www.example.com* generally points to *example.com* i.e the config for both of them are same, we could create a symbolic link named `www.example.com.conf` too instead of actual file. 121 | 122 | You will need to create **jssh config file** for each of your domains. 123 | 124 | For sub-domains you can just create *subdomain.rootdomain.conf* file with the same credentials as rootdomain except the working directory; working directory must be the document root of the subdomain/domain. In this case ssh will login with the credentials of root domain. 125 | 126 | **Note:** 127 | 128 | * The config file stores username, port, domain name/IP and working directory (in this case document root). 129 | 130 | ## Run lcget and get the certificate: 131 | Now all we have to do is to run the `lcget` command with appropriate options. The following is an example which uses a letsencrypt configuration file (All outputs are shown): 132 | 133 | ```sh 134 | ~$ lcget certonly -c neurobin.ini 135 | Requesting root privileges to run certbot... 136 | /home/user/.local/share/letsencrypt/bin/letsencrypt --text certonly -c neurobin.ini 137 | [sudo] password for user: 138 | Make sure your web server displays the following content at 139 | http://challenge.neurobin.org/.well-known/acme-challenge/s3xMuDO7WwjTUX6pbAq8hj1Ixpf4V-Rin9FBmdHDV14 before continuing: 140 | 141 | s3xMuDO7WwjTUX6pbAq8hj1Ixpf4V-Rin9FBmdHDV14.fl_1v9fRIhdgCXPAMg0ohwMfX66pkSQ_eTJjm2tejZc 142 | 143 | If you don't have HTTP server configured, you can run the following 144 | command on the target server (as root): 145 | 146 | mkdir -p /tmp/certbot/public_html/.well-known/acme-challenge 147 | cd /tmp/certbot/public_html 148 | printf "%s" s3xMuDO7WwjTUX6pbAq8hj1Ixpf4V-Rin9FBmdHDV14.fl_1v9fRIhdgCXPAMg0ohwMfX66pkSQ_eTJjm2tejZc > .well-known/acme-challenge/s3xMuDO7WwjTUX6pbAq8hj1Ixpf4V-Rin9FBmdHDV14 149 | # run only once per server: 150 | $(command -v python2 || command -v python2.7 || command -v python2.6) -c \ 151 | "import BaseHTTPServer, SimpleHTTPServer; \ 152 | s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \ 153 | s.serve_forever()" 154 | Press ENTER to continue 155 | 156 | Protocol: http:// 157 | Domain: challenge.neurobin.org 158 | File: .well-known/acme-challenge/s3xMuDO7WwjTUX6pbAq8hj1Ixpf4V-Rin9FBmdHDV14 159 | Content: s3xMuDO7WwjTUX6pbAq8hj1Ixpf4V-Rin9FBmdHDV14.fl_1v9fRIhdgCXPAMg0ohwMfX66pkSQ_eTJjm2tejZc 160 | 161 | Trying to complete challenge for challenge.neurobin.org 162 | 163 | Completing challenge... 164 | Created dir : .well-known/acme-challenge 165 | Created file: .well-known/acme-challenge/s3xMuDO7WwjTUX6pbAq8hj1Ixpf4V-Rin9FBmdHDV14 166 | 167 | Done for challenge.neurobin.org 168 | 169 | Make sure your web server displays the following content at 170 | http://www.challenge.neurobin.org/.well-known/acme-challenge/DKCumvxBheZMe_cfxA83uhIA7OrTu9RZBdxxaMEbAJ8 before continuing: 171 | 172 | DKCumvxBheZMe_cfxA83uhIA7OrTu9RZBdxxaMEbAJ8.fl_1v9fRIhdgCXPAMg0ohwMfX66pkSQ_eTJjm2tejZc 173 | 174 | If you don't have HTTP server configured, you can run the following 175 | command on the target server (as root): 176 | 177 | mkdir -p /tmp/certbot/public_html/.well-known/acme-challenge 178 | cd /tmp/certbot/public_html 179 | printf "%s" DKCumvxBheZMe_cfxA83uhIA7OrTu9RZBdxxaMEbAJ8.fl_1v9fRIhdgCXPAMg0ohwMfX66pkSQ_eTJjm2tejZc > .well-known/acme-challenge/DKCumvxBheZMe_cfxA83uhIA7OrTu9RZBdxxaMEbAJ8 180 | # run only once per server: 181 | $(command -v python2 || command -v python2.7 || command -v python2.6) -c \ 182 | "import BaseHTTPServer, SimpleHTTPServer; \ 183 | s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \ 184 | s.serve_forever()" 185 | Press ENTER to continue 186 | 187 | Protocol: http:// 188 | Domain: www.challenge.neurobin.org 189 | File: .well-known/acme-challenge/DKCumvxBheZMe_cfxA83uhIA7OrTu9RZBdxxaMEbAJ8 190 | Content: DKCumvxBheZMe_cfxA83uhIA7OrTu9RZBdxxaMEbAJ8.fl_1v9fRIhdgCXPAMg0ohwMfX66pkSQ_eTJjm2tejZc 191 | 192 | Trying to complete challenge for www.challenge.neurobin.org 193 | 194 | Completing challenge... 195 | Created dir : .well-known/acme-challenge 196 | Created file: .well-known/acme-challenge/DKCumvxBheZMe_cfxA83uhIA7OrTu9RZBdxxaMEbAJ8 197 | 198 | Done for www.challenge.neurobin.org 199 | 200 | 201 | IMPORTANT NOTES: 202 | - Congratulations! Your certificate and chain have been saved at 203 | /etc/letsencrypt/live/challenge.neurobin.org/fullchain.pem. Your 204 | cert will expire on 2016-09-04. To obtain a new or tweaked version 205 | of this certificate in the future, simply run letsencrypt again. To 206 | non-interactively renew *all* of your certificates, run 207 | "letsencrypt renew" 208 | - If you like Certbot, please consider supporting our work by: 209 | 210 | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate 211 | Donating to EFF: https://eff.org/donate-le 212 | 213 | 214 | ``` 215 | The *neurobin.ini* file: 216 | 217 | ```sh 218 | # This is an example of the kind of things you can do in a configuration file. 219 | # All flags used by the client can be configured here. Run Lets Encrypt with 220 | # --help to learn more about the available options. 221 | config-dir = /etc/letsencrypt 222 | work-dir = /home/user/.letsencrypt 223 | logs-dir = /home/user/.letsencrypt 224 | # Use a 4096 bit RSA key instead of 2048 225 | rsa-key-size = 4096 226 | 227 | # Uncomment and update to register with the specified e-mail address 228 | email = admin@neurobin.org 229 | 230 | # Uncomment and update to generate certificates for the specified domains. 231 | #Add subdomains or domains however you like. My recommendation is to put the root domain at beginning. 232 | domains = challenge.neurobin.org, www.challenge.neurobin.org 233 | 234 | 235 | # Uncomment to use a text interface instead of ncurses 236 | # Do not change this 237 | # The expect script works with text interface. 238 | text = True 239 | 240 | # Uncomment to use the standalone authenticator on port 443 241 | # authenticator = standalone 242 | # standalone-supported-challenges = tls-sni-01 243 | 244 | # Uncomment to use the webroot authenticator. Replace webroot-path with the 245 | # path to the public_html / webroot folder being served by your web server. 246 | # authenticator = webroot 247 | # webroot-path = /usr/share/nginx/html 248 | 249 | authenticator = manual 250 | manual-public-ip-logging-ok 251 | 252 | 253 | renew-by-default 254 | 255 | #Testing; comment the following block out when you are done testing and want to get the real thing. 256 | server = https://acme-staging.api.letsencrypt.org/directory 257 | debug 258 | break-my-certs 259 | 260 | #Testing opts end here 261 | 262 | ``` 263 | 264 | **Notes:** 265 | 266 | 1. The above gets a test certificate. If you edit and use the above configuration file make sure to comment out the testing block for getting a valid certificate. 267 | 2. In the above example, I didn't have to do anything at all other than running the **lcget** command. Not even giving ssh password as my ssh login uses (private and public) key pairs for authentication. 268 | 3. The above uses **Document Root** of the domain as the challenge directory. If challenge directory is elsewhere, change the jssh config file accordingly, e.g if challenge for example.com is redirected to challenge.example.com, use the document root (or credentials) of `challenge.example.com` as working directory in `example.com.conf` (jssh config file for example.com) 269 | 270 | 271 | # Caveats: 272 | 273 | Only the required codes for completing http challenge in manual mode is included for now, though this can be extended to support other modes and challenges too. 274 | 275 | # Further development: 276 | You can add other options and make **all** the things in letsencrypt automated by a little haggle with Tcl/expect. So, if you feel you can do the development and extend its' capability please fork the repository and add changes and do a pull request. I will greatly appreciate that. 277 | 278 | --------------------------------------------------------------------------------