diff --git a/changelog.md b/changelog.md index a2f8665..4cb504b 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,9 @@ -## version 0.5.1 -> 0.5.7 +## versiom 0.5.11 +- Improve docker-compose import support for alternative syntaxes +- Improve docker service creation when using force secure label (fixes few containers not liking restarting too fast when created) +- Add toggle for using insecure HTTPS targets (fixes Unifi controller) + +## version 0.5.1 -> 0.5.10 - Add Wilcard certificates support - Auto switch to Mongo 4 if CPU has no ADX - Improve setup for certificates on new install diff --git a/client/src/pages/config/routes/routeman.jsx b/client/src/pages/config/routes/routeman.jsx index f030e79..0a21790 100644 --- a/client/src/pages/config/routes/routeman.jsx +++ b/client/src/pages/config/routes/routeman.jsx @@ -46,6 +46,7 @@ const RouteManagement = ({ routeConfig, routeNames, TargetContainer, noControls Target: routeConfig.Target, UseHost: routeConfig.UseHost, Host: routeConfig.Host, + AcceptInsecureHTTPSTarget: routeConfig.AcceptInsecureHTTPSTarget === true, UsePathPrefix: routeConfig.UsePathPrefix, PathPrefix: routeConfig.PathPrefix, StripPathPrefix: routeConfig.StripPathPrefix, @@ -167,6 +168,12 @@ const RouteManagement = ({ routeConfig, routeNames, TargetContainer, noControls /> } + {formik.values.Target.startsWith('https://') && } + diff --git a/client/src/pages/servapps/containers/docker-compose.jsx b/client/src/pages/servapps/containers/docker-compose.jsx index 3dead81..db6fc31 100644 --- a/client/src/pages/servapps/containers/docker-compose.jsx +++ b/client/src/pages/servapps/containers/docker-compose.jsx @@ -1,7 +1,7 @@ // material-ui import * as React from 'react'; import { Alert, Button, Stack, Typography } from '@mui/material'; -import { WarningOutlined, PlusCircleOutlined, CopyOutlined, ExclamationCircleOutlined , SyncOutlined, UserOutlined, KeyOutlined, ArrowUpOutlined, FileZipOutlined } from '@ant-design/icons'; +import { WarningOutlined, PlusCircleOutlined, CopyOutlined, ExclamationCircleOutlined, SyncOutlined, UserOutlined, KeyOutlined, ArrowUpOutlined, FileZipOutlined } from '@ant-design/icons'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; @@ -28,13 +28,13 @@ import NewDockerService from './newService'; import yaml from 'js-yaml'; function checkIsOnline() { - API.isOnline().then((res) => { - window.location.reload(); - }).catch((err) => { - setTimeout(() => { - checkIsOnline(); - }, 1000); - }); + API.isOnline().then((res) => { + window.location.reload(); + }).catch((err) => { + setTimeout(() => { + checkIsOnline(); + }, 1000); + }); } const preStyle = { @@ -63,30 +63,25 @@ const preStyle = { marginRight: '0', } -const DockerComposeImport = ({refresh}) => { - const [step, setStep] = useState(0); - const [isLoading, setIsLoading] = useState(false); - const [openModal, setOpenModal] = useState(false); - const [dockerCompose, setDockerCompose] = useState(''); - const [service, setService] = useState({}); - const [ymlError, setYmlError] = useState(''); +const DockerComposeImport = ({ refresh }) => { + const [step, setStep] = useState(0); + const [isLoading, setIsLoading] = useState(false); + const [openModal, setOpenModal] = useState(false); + const [dockerCompose, setDockerCompose] = useState(''); + const [service, setService] = useState({}); + const [ymlError, setYmlError] = useState(''); - useEffect(() => { - if(dockerCompose === '') { - return; - } + useEffect(() => { + if (dockerCompose === '') { + return; + } + + setYmlError(''); + let doc; + let newService = {}; + try { + doc = yaml.load(dockerCompose); - setYmlError(''); - let doc; - let newService = {}; - try { - doc = yaml.load(dockerCompose); - } catch (e) { - console.log(e); - setYmlError(e.message); - return; - } - if (typeof doc === 'object' && doc !== null && Object.keys(doc).length > 0 && !doc.services && !doc.networks && !doc.volumes) { doc = { @@ -94,52 +89,66 @@ const DockerComposeImport = ({refresh}) => { } } - + // convert to the proper format - if(doc.services) { + if (doc.services) { Object.keys(doc.services).forEach((key) => { + // convert volumes - if(doc.services[key].volumes) { - let volumes = []; - doc.services[key].volumes.forEach((volume) => { - let volumeSplit = volume.split(':'); - let volumeObj = { - Source: volumeSplit[0], - Target: volumeSplit[1], - Type: volume[0] === '/' ? 'bind' : 'volume', - }; - volumes.push(volumeObj); - }); - doc.services[key].volumes = volumes; + if (doc.services[key].volumes) { + if(Array.isArray(doc.services[key].volumes)) { + let volumes = []; + doc.services[key].volumes.forEach((volume) => { + if (typeof volume === 'object') { + volumes.push(volume); + } else { + let volumeSplit = volume.split(':'); + let volumeObj = { + Source: volumeSplit[0], + Target: volumeSplit[1], + Type: volume[0] === '/' ? 'bind' : 'volume', + }; + volumes.push(volumeObj); + } + }); + doc.services[key].volumes = volumes; + } } // convert expose - if(doc.services[key].expose) { + if (doc.services[key].expose) { doc.services[key].expose = doc.services[key].expose.map((port) => { - return ''+port; + return '' + port; }) } //convert user - if(doc.services[key].user) { + if (doc.services[key].user) { doc.services[key].user = '' + doc.services[key].user; } // convert labels: - if(doc.services[key].labels) { - if(Array.isArray(doc.services[key].labels)) { + if (doc.services[key].labels) { + if (Array.isArray(doc.services[key].labels)) { let labels = {}; doc.services[key].labels.forEach((label) => { const [key, value] = label.split('='); - labels[''+key] = ''+value; + labels['' + key] = '' + value; + }); + doc.services[key].labels = labels; + } + if (typeof doc.services[key].labels == 'object') { + let labels = {}; + Object.keys(doc.services[key].labels).forEach((keylabel) => { + labels['' + keylabel] = '' + doc.services[key].labels[keylabel]; }); doc.services[key].labels = labels; } } - + // convert environment - if(doc.services[key].environment) { - if(!Array.isArray(doc.services[key].environment)) { + if (doc.services[key].environment) { + if (!Array.isArray(doc.services[key].environment)) { let environment = []; Object.keys(doc.services[key].environment).forEach((keyenv) => { environment.push(keyenv + '=' + doc.services[key].environment[keyenv]); @@ -149,100 +158,155 @@ const DockerComposeImport = ({refresh}) => { } // convert network - if(doc.services[key].networks) { - if(Array.isArray(doc.services[key].networks)) { + if (doc.services[key].networks) { + if (Array.isArray(doc.services[key].networks)) { let networks = {}; doc.services[key].networks.forEach((network) => { - networks[''+network] = {}; + if (typeof network === 'object') { + networks['' + network.name] = network; + } + else + networks['' + network] = {}; }); doc.services[key].networks = networks; } } // ensure container_name - if(!doc.services[key].container_name) { + if (!doc.services[key].container_name) { doc.services[key].container_name = key; } }); } - setService(doc); - }, [dockerCompose]); + // convert networks + if (doc.networks) { + if (Array.isArray(doc.networks)) { + let networks = {}; + doc.networks.forEach((network) => { + if (typeof network === 'object') { + networks['' + network.name] = network; + } + else + networks['' + network] = {}; + }); + doc.networks = networks; + } else { + let networks = {}; + Object.keys(doc.networks).forEach((key) => { + networks['' + key] = doc.networks[key] || {}; + }); + doc.networks = networks; + } + } - return <> - setOpenModal(false)}> - Import Docker Compose - - - {step === 0 && - }> - This is a highly experimental feature. It is recommended to use with caution. - + // convert volumes + if (doc.volumes) { + if (Array.isArray(doc.volumes)) { + let volumes = {}; + doc.volumes.forEach((volume) => { + if(!volume) { + volume = {}; + } + if (typeof volume === 'object') { + volumes['' + volume.name] = volume; + } + else + volumes['' + volume] = {}; + }); + doc.volumes = volumes; + } else { + let volumes = {}; + Object.keys(doc.volumes).forEach((key) => { + volumes['' + key] = doc.volumes[key] || {}; + }); + doc.volumes = volumes; + } + } - { - const file = e.target.files[0]; - const reader = new FileReader(); - reader.onload = (e) => { - setDockerCompose(e.target.result); - }; - reader.readAsText(file); - }} - /> + } catch (e) { + console.log(e); + setYmlError(e.message); + return; + } -
- {ymlError} -
- - setDockerCompose(e.target.value)} - sx={preStyle} - InputProps={{ - sx: { - color: '#EEE', - } - }} - rows={20}> -
} - {step === 1 && - - } -
-
- {!isLoading && - - - } -
+ setService(doc); + }, [dockerCompose]); - setOpenModal(true)} - variant="outlined" - startIcon={} - > - Import Docker Compose - - ; + return <> + setOpenModal(false)}> + Import Docker Compose + + + {step === 0 && + }> + This is a highly experimental feature. It is recommended to use with caution. + + + { + const file = e.target.files[0]; + const reader = new FileReader(); + reader.onload = (e) => { + setDockerCompose(e.target.result); + }; + reader.readAsText(file); + }} + /> + +
+ {ymlError} +
+ + setDockerCompose(e.target.value)} + sx={preStyle} + InputProps={{ + sx: { + color: '#EEE', + } + }} + rows={20}> +
} + {step === 1 && + + } +
+
+ {!isLoading && + + + } +
+ + setOpenModal(true)} + variant="outlined" + startIcon={} + > + Import Docker Compose + + ; }; export default DockerComposeImport; diff --git a/package-lock.json b/package-lock.json index 27a9b1f..38d1bfb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cosmos-server", - "version": "0.5.0-unstable", + "version": "0.5.10", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cosmos-server", - "version": "0.5.0-unstable", + "version": "0.5.10", "dependencies": { "@ant-design/colors": "^6.0.0", "@ant-design/icons": "^4.7.0", diff --git a/package.json b/package.json index 52e8b0b..69e9293 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cosmos-server", - "version": "0.5.10", + "version": "0.5.11", "description": "", "main": "test-server.js", "bugs": { @@ -56,10 +56,10 @@ "client": "vite", "client-build": "vite build --base=/ui/", "start": "env COSMOS_HOSTNAME=localhost CONFIG_FILE=./config_dev.json EZ=UTC build/cosmos", - "build": " sh build.sh", + "build": "sh build.sh", "dev": "npm run build && npm run start", - "dockerdevbuild": "sh build.sh && npm run client-build && docker build --tag cosmos-dev .", - "dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run -d -p 80:80 -p 443:443 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev", + "dockerdevbuild": "sh build.sh && docker build --tag cosmos-dev .", + "dockerdevrun": "docker stop cosmos-dev; docker rm cosmos-dev; docker run -d -p 80:80 -p 443:443 -e DOCKER_HOST=tcp://host.docker.internal:2375 -e COSMOS_MONGODB=$MONGODB -e COSMOS_LOG_LEVEL=DEBUG -v /:/mnt/host --restart=unless-stopped -h cosmos-dev --name cosmos-dev cosmos-dev", "dockerdev": "npm run dockerdevbuild && npm run dockerdevrun", "demo": "vite build --base=/ui/ --mode demo", "devdemo": "vite --mode demo" diff --git a/readme.md b/readme.md index 54e1bae..5183944 100644 --- a/readme.md +++ b/readme.md @@ -110,7 +110,7 @@ Authentication is very hard (how do you check the password match? What encryptio Installation is simple using Docker: ``` -docker run -d -p 80:80 -p 443:443 --name cosmos-server -h cosmos-server --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/cosmos:/config azukaar/cosmos-server:latest +docker run -d -p 80:80 -p 443:443 --name cosmos-server -h cosmos-server --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /:/mnt/host -v /var/lib/cosmos:/config azukaar/cosmos-server:latest ``` Once installed, simply go to `http://your-server-ip` and follow the instructions of the setup wizard. diff --git a/src/docker/api_blueprint.go b/src/docker/api_blueprint.go index 5c7bfc6..e434693 100644 --- a/src/docker/api_blueprint.go +++ b/src/docker/api_blueprint.go @@ -22,6 +22,12 @@ import ( "github.com/azukaar/cosmos-server/src/utils" ) +type ContainerCreateRequestServiceNetwork struct { + Aliases []string `json:"aliases,omitempty"` + IPV4Address string `json:"ipv4_address,omitempty"` + IPV6Address string `json:"ipv6_address,omitempty"` +} + type ContainerCreateRequestContainer struct { Name string `json:"container_name"` Image string `json:"image"` @@ -29,12 +35,8 @@ type ContainerCreateRequestContainer struct { Labels map[string]string `json:"labels"` Ports []string `json:"ports"` Volumes []mount.Mount `json:"volumes"` - Networks map[string]struct { - Aliases []string `json:"aliases,omitempty"` - IPV4Address string `json:"ipv4_address,omitempty"` - IPV6Address string `json:"ipv6_address,omitempty"` - } `json:"networks"` - Routes []utils.ProxyRouteConfig `json:"routes"` + Networks map[string]ContainerCreateRequestServiceNetwork `json:"networks"` + Routes []utils.ProxyRouteConfig `json:"routes"` RestartPolicy string `json:"restart,omitempty"` Devices []string `json:"devices"` @@ -100,7 +102,7 @@ type ContainerCreateRequestNetwork struct { type DockerServiceCreateRequest struct { Services map[string]ContainerCreateRequestContainer `json:"services"` - Volumes []ContainerCreateRequestVolume `json:"volumes"` + Volumes map[string]ContainerCreateRequestVolume `json:"volumes"` Networks map[string]ContainerCreateRequestNetwork `json:"networks"` } @@ -137,6 +139,9 @@ func Rollback(actions []DockerServiceCreateRollback , w http.ResponseWriter, flu flusher.Flush() } case "network": + if os.Getenv("HOSTNAME") != "" { + DockerClient.NetworkDisconnect(DockerContext, action.Name, os.Getenv("HOSTNAME"), true) + } err := DockerClient.NetworkRemove(DockerContext, action.Name) if err != nil { utils.Error("Rollback: Network", err) @@ -220,6 +225,48 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock var rollbackActions []DockerServiceCreateRollback var err error + // check if services have the cosmos-force-network-secured label + for serviceName, service := range serviceRequest.Services { + utils.Log(fmt.Sprintf("Checking service %s...", serviceName)) + fmt.Fprintf(w, "Checking service %s...\n", serviceName) + flusher.Flush() + + if service.Labels["cosmos-force-network-secured"] == "true" { + utils.Log(fmt.Sprintf("Forcing secure %s...", serviceName)) + fmt.Fprintf(w, "Forcing secure %s...\n", serviceName) + flusher.Flush() + + newNetwork, errNC := CreateCosmosNetwork() + if errNC != nil { + utils.Error("CreateService: Network", err) + fmt.Fprintf(w, "[ERROR] Network %s cant be created\n", newNetwork) + flusher.Flush() + Rollback(rollbackActions, w, flusher) + return err + } + + service.Labels["cosmos-network-name"] = newNetwork + + AttachNetworkToCosmos(newNetwork) + + if service.Networks == nil { + service.Networks = make(map[string]ContainerCreateRequestServiceNetwork) + } + + service.Networks[newNetwork] = ContainerCreateRequestServiceNetwork{} + + rollbackActions = append(rollbackActions, DockerServiceCreateRollback{ + Action: "remove", + Type: "network", + Name: newNetwork, + }) + + utils.Log(fmt.Sprintf("Created secure network %s", newNetwork)) + fmt.Fprintf(w, "Created secure network %s\n", newNetwork) + flusher.Flush() + } + } + // Create networks for networkToCreateName, networkToCreate := range serviceRequest.Networks { utils.Log(fmt.Sprintf("Creating network %s...", networkToCreateName)) @@ -391,11 +438,32 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock // Create missing folders for bind mounts for _, newmount := range container.Volumes { if newmount.Type == mount.TypeBind { - if _, err := os.Stat(newmount.Source); os.IsNotExist(err) { - err := os.MkdirAll(newmount.Source, 0755) + newSource := newmount.Source + + if os.Getenv("HOSTNAME") != "" { + if _, err := os.Stat("/mnt/host"); os.IsNotExist(err) { + utils.Error("CreateService: Unable to create directory for bind mount in the host directory. Please mount the host / in Cosmos with -v /:/mnt/host to enable folder creations, or create the bind folder yourself", err) + fmt.Fprintf(w, "[ERROR] Unable to create directory for bind mount in the host directory. Please mount the host / in Cosmos with -v /:/mnt/host to enable folder creations, or create the bind folder yourself: "+err.Error()) + flusher.Flush() + Rollback(rollbackActions, w, flusher) + return err + } + newSource = "/mnt/host" + newSource + } + + utils.Log(fmt.Sprintf("Checking directory %s for bind mount", newSource)) + fmt.Fprintf(w, "Checking directory %s for bind mount\n", newSource) + flusher.Flush() + + if _, err := os.Stat(newSource); os.IsNotExist(err) { + utils.Log(fmt.Sprintf("Not found. Creating directory %s for bind mount", newSource)) + fmt.Fprintf(w, "Not found. Creating directory %s for bind mount\n", newSource) + flusher.Flush() + + err := os.MkdirAll(newSource, 0755) if err != nil { - utils.Error("CreateService: Unable to create directory for bind mount", err) - fmt.Fprintf(w, "[ERROR] Unable to create directory for bind mount: "+err.Error()) + utils.Error("CreateService: Unable to create directory for bind mount. Make sure parent directories exist, and that Cosmos has permissions to create directories in the host directory", err) + fmt.Fprintf(w, "[ERROR] Unable to create directory for bind mount. Make sure parent directories exist, and that Cosmos has permissions to create directories in the host directory for bind mount: "+err.Error()) flusher.Flush() Rollback(rollbackActions, w, flusher) return err @@ -411,7 +479,7 @@ func CreateService(w http.ResponseWriter, req *http.Request, serviceRequest Dock } else { uid, _ := strconv.Atoi(userInfo.Uid) gid, _ := strconv.Atoi(userInfo.Gid) - err = os.Chown(newmount.Source, uid, gid) + err = os.Chown(newSource, uid, gid) if err != nil { utils.Error("CreateService: Unable to change ownership of directory", err) fmt.Fprintf(w, "[ERROR] Unable to change ownership of directory: "+err.Error()) diff --git a/src/docker/api_updateContainer.go b/src/docker/api_updateContainer.go index 33f9a84..5f203a6 100644 --- a/src/docker/api_updateContainer.go +++ b/src/docker/api_updateContainer.go @@ -4,8 +4,6 @@ import ( "encoding/json" "net/http" "os" - "os/user" - "strconv" "github.com/azukaar/cosmos-server/src/utils" containerType "github.com/docker/docker/api/types/container" @@ -86,33 +84,6 @@ func UpdateContainerRoute(w http.ResponseWriter, req *http.Request) { } } if(form.Volumes != nil) { - // Create missing folders for bind mounts - for _, newmount := range form.Volumes { - if newmount.Type == mount.TypeBind { - if _, err := os.Stat(newmount.Source); os.IsNotExist(err) { - err := os.MkdirAll(newmount.Source, 0755) - if err != nil { - utils.Error("UpdateService: Unable to create directory for bind mount", err) - utils.HTTPError(w, "Unable to create directory for bind mount: "+err.Error(), http.StatusInternalServerError, "DS004") - return - } - - // Change the ownership of the directory to the container.User - userInfo, err := user.Lookup(container.Config.User) - if err != nil { - utils.Error("UpdateService: Unable to lookup user", err) - } else { - uid, _ := strconv.Atoi(userInfo.Uid) - gid, _ := strconv.Atoi(userInfo.Gid) - err = os.Chown(newmount.Source, uid, gid) - if err != nil { - utils.Error("UpdateService: Unable to change ownership of directory", err) - } - } - } - } - } - container.HostConfig.Mounts = form.Volumes container.HostConfig.Binds = []string{} } diff --git a/src/docker/docker.go b/src/docker/docker.go index 3733428..c80e171 100644 --- a/src/docker/docker.go +++ b/src/docker/docker.go @@ -5,12 +5,17 @@ import ( "errors" "time" "bufio" + "os" + "os/user" + "fmt" "strings" + "strconv" "github.com/azukaar/cosmos-server/src/utils" "github.com/docker/docker/client" // natting "github.com/docker/go-connections/nat" "github.com/docker/docker/api/types/container" + mountType "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types" ) @@ -111,6 +116,49 @@ func EditContainer(oldContainerID string, newConfig types.ContainerJSON, noLock oldContainer := newConfig if(oldContainerID != "") { + // create missing folders + + for _, newmount := range newConfig.HostConfig.Mounts { + if newmount.Type == mountType.TypeBind { + newSource := newmount.Source + + if os.Getenv("HOSTNAME") != "" { + if _, err := os.Stat("/mnt/host"); os.IsNotExist(err) { + utils.Error("EditContainer: Unable to create directory for bind mount in the host directory. Please mount the host / in Cosmos with -v /:/mnt/host to enable folder creations, or create the bind folder yourself", err) + return "", errors.New("Unable to create directory for bind mount in the host directory. Please mount the host / in Cosmos with -v /:/mnt/host to enable folder creations, or create the bind folder yourself") + } + newSource = "/mnt/host" + newSource + } + + utils.Log(fmt.Sprintf("Checking directory %s for bind mount", newSource)) + + if _, err := os.Stat(newSource); os.IsNotExist(err) { + utils.Log(fmt.Sprintf("Not found. Creating directory %s for bind mount", newSource)) + + err := os.MkdirAll(newSource, 0755) + if err != nil { + utils.Error("EditContainer: Unable to create directory for bind mount", err) + return "", errors.New("Unable to create directory for bind mount. Make sure parent directories exist, and that Cosmos has permissions to create directories in the host directory") + } + + if newConfig.Config.User != "" { + // Change the ownership of the directory to the container.User + userInfo, err := user.Lookup(newConfig.Config.User) + if err != nil { + utils.Error("EditContainer: Unable to lookup user", err) + } else { + uid, _ := strconv.Atoi(userInfo.Uid) + gid, _ := strconv.Atoi(userInfo.Gid) + err = os.Chown(newSource, uid, gid) + if err != nil { + utils.Error("EditContainer: Unable to change ownership of directory", err) + } + } + } + } + } + } + utils.Log("EditContainer - Container updating. Retriveing currently running " + oldContainerID) var err error diff --git a/src/proxy/routeTo.go b/src/proxy/routeTo.go index e12b0b0..f6072ec 100644 --- a/src/proxy/routeTo.go +++ b/src/proxy/routeTo.go @@ -4,12 +4,13 @@ import ( "net/http" "net/http/httputil" "net/url" + "crypto/tls" spa "github.com/roberthodgen/spa-server" "github.com/azukaar/cosmos-server/src/utils" ) // NewProxy takes target host and creates a reverse proxy -func NewProxy(targetHost string) (*httputil.ReverseProxy, error) { +func NewProxy(targetHost string, AcceptInsecureHTTPSTarget bool) (*httputil.ReverseProxy, error) { url, err := url.Parse(targetHost) if err != nil { return nil, err @@ -17,6 +18,12 @@ func NewProxy(targetHost string) (*httputil.ReverseProxy, error) { proxy := httputil.NewSingleHostReverseProxy(url) + if AcceptInsecureHTTPSTarget && url.Scheme == "https" { + proxy.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + } + proxy.ModifyResponse = func(resp *http.Response) error { utils.Debug("Response from backend: " + resp.Status) utils.Debug("URL was " + resp.Request.URL.String()) @@ -35,7 +42,7 @@ func RouteTo(route utils.ProxyRouteConfig) http.Handler { routeType := route.Mode if(routeType == "SERVAPP" || routeType == "PROXY") { - proxy, err := NewProxy(destination) + proxy, err := NewProxy(destination, route.AcceptInsecureHTTPSTarget) if err != nil { utils.Error("Create Route", err) } diff --git a/src/utils/types.go b/src/utils/types.go index 71aff15..1a473ee 100644 --- a/src/utils/types.go +++ b/src/utils/types.go @@ -148,6 +148,7 @@ type ProxyRouteConfig struct { Mode ProxyMode BlockCommonBots bool BlockAPIAbuse bool + AcceptInsecureHTTPSTarget bool } type EmailConfig struct { diff --git a/vite.config.js b/vite.config.js index cc8210f..da5d2a2 100644 --- a/vite.config.js +++ b/vite.config.js @@ -8,7 +8,6 @@ export default defineConfig({ build: { outDir: '../static', }, - // base: '/ui', server: { proxy: { '/cosmos/api': { @@ -16,6 +15,10 @@ export default defineConfig({ secure: false, ws: true, } + }, + + watch: { + usePolling: true } } })