diff --git a/actions.go b/actions.go index 9874d9b..e92f7b1 100644 --- a/actions.go +++ b/actions.go @@ -48,7 +48,7 @@ func writeServers() error { return nil } -func sendFileToAllServers(filePath string) error { +func sendFileToAllServers(filePath, cert_idx string) error { var theError error numservers := len(servers) c := make(chan string) @@ -65,7 +65,7 @@ func sendFileToAllServers(filePath string) error { } log.Println("Parallel execution send file to server: " + srv + "...") - err := sendFileToServer(filePath, srv) + err := sendFileToServer(filePath, srv, cert_idx) if err != nil { log.Println(err.Error()) theError = err @@ -92,17 +92,18 @@ func sendFileToAllServers(filePath string) error { return theError //if any one or more fail, return an error for it (the last one that fails) } -func sendFileToServer(filePath, server string) error { +func sendFileToServer(filePath, server, cert_idx string) error { log.Println("Send file " + filePath + " to " + server + " starting...") _, fileName := path.Split(filePath) - dest := strings.SplitN(fileName, "__", 2)[0] //cert__abcdef1234567890.tmpfile --> "cert" + fileType := strings.SplitN(fileName, "__", 2)[0] //cert__abcdef1234567890.tmpfile --> "cert" data, err := os.Open(filePath) if err != nil { return errors.New("sendFileToServer: Could not open temporary file " + filePath + ": " + err.Error()) } - url := syncScheme + server + ":" + syncPort + "/api/file/upload/" + dest - log.Println("Send file " + filePath + " to " + url + "...") + //url := syncScheme + server + ":" + syncPort + "/api/file/upload/" + fileType + "/" + fmt.Sprintf("%02d", cert_idx) + url := syncScheme + server + ":" + syncPort + "/api/file/upload/" + fileType + "/" + cert_idx + log.Println("Send file '" + filePath + "' to " + url + "...") req, err := http.NewRequest("PUT", url, data) if err != nil { @@ -133,7 +134,7 @@ func sendFileToServer(filePath, server string) error { log.Println(errorString) return errors.New(errorString) } - log.Println("Upload [" + dest + "] to " + server + " success!") + log.Println("Upload [" + fileType + "] to " + server + " success!") return nil } @@ -160,6 +161,9 @@ func renew(cert_idx int) error { log.Println(domainlist) } + // GetSSL Expected WebDAV Format: (HTTPS ONLY!) + // ";davs:davsuser:davspassword:{DOMAIN}:443:/path" + //ACL string aclstring := appconf.LetsEncryptValidationPath if appconf.SyncType == "ssh" { @@ -190,10 +194,11 @@ func renew(cert_idx int) error { if server == appconf.Hostname { continue } - domain_cert_location += ";ssh:" + appconf.Username + "@" + server + ":" + appconf.TLSCertPath + fmt.Sprintf("%02d", cert_idx) + ".crt" //domain_cert_location += ";davs:leapi:" + appconf.SecretKey + ":" + server + ":" + syncPort + ":/api/file/upload/cert" + domain_cert_location += ";ssh:" + appconf.Username + "@" + server + ":" + appconf.TLSCertPath + fmt.Sprintf("%02d", cert_idx) + ".crt" } } else { //file sync type is HTTPS + // ;davs:user:pass:hostname:port:/api/file/sync/cert/{cert_idx} domain_cert_location += ";davs:" + appconf.Username + ":" + appconf.SecretKey + ":" + appconf.Hostname + ":" + appconf.HTTPS_ServerPort + ":/api/file/sync/cert/" + fmt.Sprintf("%02d", cert_idx) } err = os.Setenv("DOMAIN_CERT_LOCATION", domain_cert_location) @@ -207,8 +212,8 @@ func renew(cert_idx int) error { if server == appconf.Hostname { continue } - domain_key_location += ";ssh:" + appconf.Username + "@" + server + ":" + appconf.TLSKeyPath + fmt.Sprintf("%02d", cert_idx) + ".key" //domain_key_location += ";davs:leapi:" + appconf.SecretKey + ":" + server + ":" + syncPort + ":/api/file/upload/key" + domain_key_location += ";ssh:" + appconf.Username + "@" + server + ":" + appconf.TLSKeyPath + fmt.Sprintf("%02d", cert_idx) + ".key" } } else { //file sync type is HTTPS domain_key_location += ";davs:" + appconf.Username + ":" + appconf.SecretKey + ":" + appconf.Hostname + ":" + appconf.HTTPS_ServerPort + ":/api/file/sync/key/" + fmt.Sprintf("%02d", cert_idx) @@ -224,8 +229,8 @@ func renew(cert_idx int) error { if server == appconf.Hostname { continue } - domain_chain_location += ";ssh:" + appconf.Username + "@" + server + ":" + appconf.TLSChainPath + fmt.Sprintf("%02d", cert_idx) + ".crt" //domain_chain_location += ";davs:leapi:" + appconf.SecretKey + ":" + server + ":" + syncPort + ":/api/file/upload/chain" + domain_chain_location += ";ssh:" + appconf.Username + "@" + server + ":" + appconf.TLSChainPath + fmt.Sprintf("%02d", cert_idx) + ".crt" } } else { //file sync type is HTTPS domain_chain_location += ";davs:" + appconf.Username + ":" + appconf.SecretKey + ":" + appconf.Hostname + ":" + appconf.HTTPS_ServerPort + ":/api/file/sync/chain/" + fmt.Sprintf("%02d", cert_idx) @@ -235,14 +240,14 @@ func renew(cert_idx int) error { return errors.New("RENEW: error setting DOMAIN_CHAIN_LOCATION environment variable: " + err.Error()) } - domain_pem_location := appconf.TLSPEMPath + domain_pem_location := appconf.TLSPEMPath + fmt.Sprintf("%02d", cert_idx) + ".pem" if appconf.SyncType == "ssh" { for _, server := range servers { if server == appconf.Hostname { continue } - domain_pem_location += ";ssh:" + appconf.Username + "@" + server + ":" + appconf.TLSPEMPath + fmt.Sprintf("%02d", cert_idx) + ".pem" //domain_pem_location += ";davs:leapi:" + appconf.SecretKey + ":" + server + ":" + syncPort + ":/api/file/upload/pem" + domain_pem_location += ";ssh:" + appconf.Username + "@" + server + ":" + appconf.TLSPEMPath + fmt.Sprintf("%02d", cert_idx) + ".pem" } } else { //file sync type is HTTPS domain_pem_location += ";davs:" + appconf.Username + ":" + appconf.SecretKey + ":" + appconf.Hostname + ":" + appconf.HTTPS_ServerPort + ":/api/file/sync/pem/" + fmt.Sprintf("%02d", cert_idx) @@ -252,15 +257,15 @@ func renew(cert_idx int) error { return errors.New("RENEW: error setting DOMAIN_PEM_LOCATION environment variable: " + err.Error()) } - //these parameters don't seem to be respected by gettssl from environment variables, so write them to config file: - ca_cert_location := appconf.TLSCAPath + //these parameters don't seem to be respected by GetSSL from environment variables, so write them to config file: + ca_cert_location := appconf.TLSCAPath + ".crt" if appconf.SyncType == "ssh" { for _, server := range servers { if server == appconf.Hostname { continue } - ca_cert_location += ";ssh:" + appconf.Username + "@" + server + ":" + appconf.TLSCAPath + fmt.Sprintf("%02d", cert_idx) + ".crt" //ca_cert_location += ";davs:leapi:" + appconf.SecretKey + ":" + server + ":" + syncPort + ":/api/file/upload/ca" + ca_cert_location += ";ssh:" + appconf.Username + "@" + server + ":" + appconf.TLSCAPath + fmt.Sprintf("%02d", cert_idx) + ".crt" } } else { //file sync type is HTTPS ca_cert_location += ";davs:" + appconf.Username + ":" + appconf.SecretKey + ":" + appconf.Hostname + ":" + appconf.HTTPS_ServerPort + ":/api/file/sync/ca/" + fmt.Sprintf("%02d", cert_idx) diff --git a/api.go b/api.go index 95a59d2..f546c61 100644 --- a/api.go +++ b/api.go @@ -101,6 +101,7 @@ func apiUpload(c echo.Context) error { func apiUploadSync(c echo.Context) error { fileType := c.Param("fileType") + cert_idx := c.Param("cert_idx") r := c.Request() //Read the upload data @@ -108,22 +109,22 @@ func apiUploadSync(c echo.Context) error { body, err := ioutil.ReadAll(io.LimitReader(r.Body, blimit)) if err != nil { log.Println(err.Error()) - return c.JSON(errorOut(http.StatusInternalServerError, "Error reading post body: "+err.Error())) + return c.JSON(errorOut(http.StatusInternalServerError, "Error reading PUT body: "+err.Error())) } uuid := generateUUID() filePath := appconf.SrvDir + "/" + fileType + "__" + uuid + ".tmpfile" + log.Println("Received PUT for sync to " + r.RequestURI) + log.Println("Writing to " + filePath) + //Write the file err = ioutil.WriteFile(filePath, body, 0644) if err != nil { return c.JSON(errorOut(http.StatusInternalServerError, "Could not write temporary file: "+err.Error())) } - log.Println("Received PUT for sync to " + r.RequestURI) - log.Println("Writing to " + filePath) - - err = sendFileToAllServers(filePath) + err = sendFileToAllServers(filePath, cert_idx) if err != nil { log.Println(err.Error()) return c.JSON(errorOut(http.StatusInternalServerError, "Error sending file "+filePath+" to other servers: "+err.Error())) diff --git a/leapi_config.json.sample b/leapi_config.json.sample index fe3f8da..a4c8d87 100644 --- a/leapi_config.json.sample +++ b/leapi_config.json.sample @@ -1,7 +1,7 @@ //RuhNet LEAPI Config file //configDir set by environment variable LEAPI_CONFDIR, otherwise assumed to be /opt/leapi or ./ { - "hostname":"web1.mydomain.net", //hostname or IP of this particular server; must match the server you add to LEAPI. You can use "-" to use the system hostname (must be resolvable by other LEAPI systems). + "hostname":"web1.mydomain.net", //hostname or IP of this particular server; MUST match the server you add to LEAPI. You can use "-" to use the system hostname (must be resolvable by other LEAPI systems). "primary_domain":"mydomain.net", //the main base domain that is always present "srv_dir":"/opt/leapi", //LEAPI installed directory "sync_type":"https", //method of transferring files between LEAPI hosts. "ssh" or "https" @@ -9,16 +9,17 @@ "log_file":"/var/log/leapi.log", "debug":false, "frontend_url":"admin.mydomain.net", //the frontend URL, if any (for CORS). Use "-" if none. - "http_server_port":"80", //set to 80 if you aren't using a separate web server - "https_server_port":"-", //set to "-" to disable HTTPS (mainly useful for initial setup) - "tls_cert_path_prefix":"/etc/ssl/cert", + "http_server_port":"80", //set to 80 if you are not using a separate web server or proxy. "-" will assume port 80. + "https_server_enable":false, //set to false to disable HTTPS listener (for initial setup, or for using a separate web server/proxy) + "https_server_port":"-", //the port your HTTPS server is running on, whether LEAPI or an external web server/proxy. Set to "-" for default (port 443) + "tls_cert_path_prefix":"/etc/ssl/cert", //file paths DO NOT INCLUDE EXTENSION. "/etc/ssl/cert" will write files "/etc/ssl/cert01.crt", "/etc/ssl/cert02.crt", etc. "tls_key_path_prefix":"/etc/ssl/privkey", "tls_chain_path_prefix":"/etc/ssl/chain", "tls_pem_path_prefix":"/etc/ssl/domain", "tls_ca_path_prefix":"/etc/ssl/ca", + "max_domains_per_cert":100, //100 max "letsencrypt_validation_path":"-", //if "-", LEAPI handles this and you don't use a separate web server "renew_allow_days":"70", - "max_domains_per_cert":100, "reload_command":"systemctl reload leapi ; systemctl restart nginx", "check_port":"443", //the port/service to check to verify cert installation (https/imap/imaps/xmpp/ftp/smtp) "production":false, //if false, the staging LE server will be used. Set true to use the rate limited real server. diff --git a/main.go b/main.go index 0edd842..174d12e 100644 --- a/main.go +++ b/main.go @@ -60,6 +60,7 @@ type LEAPIConfig struct { Debug bool `json:"debug"` HTTP_ServerPort string `json:"http_server_port"` HTTPS_ServerPort string `json:"https_server_port"` + HTTPS_ServerEnable bool `json:"https_server_enable"` TLSCertPath string `json:"tls_cert_path_prefix"` TLSKeyPath string `json:"tls_key_path_prefix"` TLSChainPath string `json:"tls_chain_path_prefix"` @@ -192,8 +193,21 @@ func main() { } } + //set ports to defaults if "-" or zero + if appconf.HTTP_ServerPort == "-" || appconf.HTTP_ServerPort == "0" { + appconf.HTTP_ServerPort = "80" + } + if appconf.HTTPS_ServerPort == "-" || appconf.HTTPS_ServerPort == "0" { + appconf.HTTPS_ServerPort = "443" + } + + //set sync port syncPort = appconf.HTTP_ServerPort - if appconf.LetsEncryptValidationPath == "-" { + if appconf.SyncType == "https" { + syncPort = appconf.HTTPS_ServerPort + } + + if appconf.LetsEncryptValidationPath == "-" || appconf.LetsEncryptValidationPath == "" { appconf.LetsEncryptValidationPath = appconf.SrvDir + "/acme-challenge" } @@ -287,7 +301,7 @@ func main() { // HTTP SERVERS CONFIG: //TLS Server - if appconf.HTTPS_ServerPort != "-" { //disable HTTPS if port is zero + if appconf.HTTPS_ServerEnable { syncScheme = "https://" syncPort = appconf.HTTPS_ServerPort diff --git a/sync.go b/sync.go index 1bb1464..ed32919 100644 --- a/sync.go +++ b/sync.go @@ -139,6 +139,7 @@ func syncServersFromHost(host string) error { return nil } +// Get domains from server and write what is received to this server's domains.json file. func syncDomainsFromHost(host string) error { var theError error req, err := http.NewRequest("GET", syncScheme+host+":"+syncPort+"/api/domains", nil)