diff --git a/.dockerignore b/.dockerignore index 4134e5f..61386ed 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,3 @@ +dev +docs client/node_modules diff --git a/README.md b/README.md index ed9d542..7fdc403 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,6 @@ You only need `.env.example`, `docker-compose.yml` and `traefik/`. #### Do I need to use traefik? - Traefik needs to be used to forward traffic to the rooms. You can put nginx in front of it, but not replace it. -- Your domain name specified for traefik must match the domain name, that your proxy connects to. In docker-compose it is the service name. - See example configuration for [nginx](docs/nginx). You can use `docker-compose.http.yml` that will expose this service to `8080` or any port. Authentication is optional. @@ -86,7 +85,7 @@ Update your email in `traefik/traefik.yml`. You need to pull all your images, that you want to use with neko-room. Otherwise, you might get this error: `Error response from daemon: No such image:` (see issue #1). ```sh -docker pull m1k1o/neko:latest +docker pull m1k1o/neko:firefox docker pull m1k1o/neko:chromium # etc... ``` diff --git a/docs/dind/.gitignore b/docs/dind/.gitignore new file mode 100644 index 0000000..1269488 --- /dev/null +++ b/docs/dind/.gitignore @@ -0,0 +1 @@ +data diff --git a/docs/dind/Dockerfile b/docs/dind/Dockerfile new file mode 100644 index 0000000..b3707c7 --- /dev/null +++ b/docs/dind/Dockerfile @@ -0,0 +1,7 @@ +FROM docker:dind + +COPY nrooms-* / + +VOLUME [ "/data" ] + +ENTRYPOINT [ "/nrooms-entrypoint.sh" ] diff --git a/docs/dind/README.md b/docs/dind/README.md new file mode 100644 index 0000000..f27c79c --- /dev/null +++ b/docs/dind/README.md @@ -0,0 +1,18 @@ +# dind: Docker in Docker + +Neko rooms manages neko containers in docker and routes them using traefik. This is whole implementation put inside docker, that runs in docker. It is additional layer of security, but still not perfect (because dind requires `--privileged`). + +This overhead of putting docker in docker can have negative impact on the usability, therefore users are encouraged to **not deploy neko-rooms using dind** method. + +However, there are some usecases, when this might come in handy: + - just testing out neko-rooms + - absolutely needed additional security layer + - developing neko-rooms + +## Pull images + +In order to pull new images run: + +```sh +docker-compose exec neko-rooms docker pull m1k1o/neko:chromium +``` diff --git a/docs/dind/docker-compose.yml b/docs/dind/docker-compose.yml new file mode 100644 index 0000000..94cb6d8 --- /dev/null +++ b/docs/dind/docker-compose.yml @@ -0,0 +1,19 @@ +version: "3" + +services: + neko-rooms: + build: "./" + restart: "unless-stopped" + privileged: true + environment: + - "TZ=Europe/Vienna" + - "NEKO_ROOMS_EPR=59000-59049" + - "NEKO_ROOMS_NAT1TO1=10.8.0.1" # IP address of your server + - "NEKO_ROOMS_INSTANCE_URL=http://10.8.0.1:8080/" # external URL + volumes: + - ./data/storage:/data + - ./data/docker:/var/lib/docker + - ./data/certs:/certs + ports: + - 8080:80 + - 59000-59049:59000-59049/udp diff --git a/docs/dind/nrooms-entrypoint.sh b/docs/dind/nrooms-entrypoint.sh new file mode 100755 index 0000000..1f7dfc9 --- /dev/null +++ b/docs/dind/nrooms-entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +/nrooms-start.sh & +source /usr/local/bin/dockerd-entrypoint.sh diff --git a/docs/dind/nrooms-start.sh b/docs/dind/nrooms-start.sh new file mode 100755 index 0000000..be428ef --- /dev/null +++ b/docs/dind/nrooms-start.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +# +# wait for docker to start +# + +until docker ps +do + echo "waiting for docker..." + sleep 1 +done + +# +# create traefik network +# + +docker network create --attachable traefik + +# +# (re)start traefik +# + +docker stop traefik +docker rm traefik +docker run -d \ + --restart unless-stopped \ + --name traefik \ + --network=traefik \ + -p "80:80" \ + -v "/var/run/docker.sock:/var/run/docker.sock:ro" \ + -e "TZ=${TZ}" \ + traefik:2.4 \ + --providers.docker=true \ + --providers.docker.watch=true \ + --providers.docker.exposedbydefault=false \ + --providers.docker.network=traefik \ + --entrypoints.web.address=:80; + +# pull some neko images... +docker pull m1k1o/neko:firefox +docker pull m1k1o/neko:chromium + +# +# (re)start neko-rooms +# + +docker stop nrooms +docker rm nrooms +docker run -t \ + --restart unless-stopped \ + --name nrooms \ + --network=traefik \ + -v "/var/run/docker.sock:/var/run/docker.sock" \ + -v "/data:/data" \ + -e "TZ=${TZ}" \ + -e "NEKO_ROOMS_EPR=${NEKO_ROOMS_EPR}" \ + -e "NEKO_ROOMS_NAT1TO1=${NEKO_ROOMS_NAT1TO1}" \ + -e "NEKO_ROOMS_INSTANCE_URL=${NEKO_ROOMS_INSTANCE_URL}" \ + -e "NEKO_ROOMS_TRAEFIK_DOMAIN=*" \ + -e "NEKO_ROOMS_TRAEFIK_ENTRYPOINT=web" \ + -e "NEKO_ROOMS_TRAEFIK_NETWORK=traefik" \ + -e "NEKO_ROOMS_STORAGE_ENABLED=true" \ + -e "NEKO_ROOMS_STORAGE_INTERNAL=/data" \ + -e "NEKO_ROOMS_STORAGE_EXTERNAL=/data" \ + -l "traefik.enable=true" \ + -l "traefik.http.services.neko-rooms-frontend.loadbalancer.server.port=8080" \ + -l "traefik.http.routers.neko-rooms.entrypoints=web" \ + -l 'traefik.http.routers.neko-rooms.rule=HostRegexp(`{host:.+}`)' \ + -l 'traefik.http.routers.neko-rooms.priority=1' \ + m1k1o/neko-rooms:latest; diff --git a/docs/nginx/docker-compose.yml b/docs/nginx/docker-compose.yml index f208250..62132d4 100644 --- a/docs/nginx/docker-compose.yml +++ b/docs/nginx/docker-compose.yml @@ -27,7 +27,7 @@ services: - "TZ=Europe/Vienna" - "NEKO_ROOMS_EPR=59000-59049" - "NEKO_ROOMS_NAT1TO1=10.8.0.1" # IP address of your server - - "NEKO_ROOMS_TRAEFIK_DOMAIN=traefik" # traefik domain (name of the service) + - "NEKO_ROOMS_TRAEFIK_DOMAIN=*" - "NEKO_ROOMS_TRAEFIK_ENTRYPOINT=web" - "NEKO_ROOMS_TRAEFIK_NETWORK=neko-rooms-traefik" - "NEKO_ROOMS_INSTANCE_URL=https://10.8.0.1:8080/" # external URL @@ -37,7 +37,8 @@ services: - "traefik.enable=true" - "traefik.http.services.neko-rooms-frontend.loadbalancer.server.port=8080" - "traefik.http.routers.neko-rooms.entrypoints=web" - - "traefik.http.routers.neko-rooms.rule=Host(`traefik`)" # traefik domain (name of the service) + - "traefik.http.routers.neko-rooms.rule=HostRegexp(`{host:.+}`)" + - "traefik.http.routers.neko-rooms.priority=1" # # This should be replaced by your own existing nginx instance diff --git a/install b/install index 7a92fe7..74627d9 100755 --- a/install +++ b/install @@ -203,7 +203,7 @@ echo "[Y] Got all settings..." # Create env # -NEKO_IMAGES=(m1k1o/neko:latest m1k1o/neko:chromium m1k1o/neko:google-chrome) +NEKO_IMAGES=(m1k1o/neko:firefox m1k1o/neko:chromium m1k1o/neko:google-chrome) { echo "TZ=${TZ}" diff --git a/internal/config/room.go b/internal/config/room.go index 4ef3848..b288014 100644 --- a/internal/config/room.go +++ b/internal/config/room.go @@ -46,10 +46,11 @@ func (Room) Init(cmd *cobra.Command) error { } cmd.PersistentFlags().StringSlice("neko_images", []string{ - "m1k1o/neko:latest", + "m1k1o/neko:firefox", "m1k1o/neko:chromium", "m1k1o/neko:google-chrome", "m1k1o/neko:ungoogled-chromium", + "m1k1o/neko:brave", "m1k1o/neko:tor-browser", "m1k1o/neko:vlc", "m1k1o/neko:vncviewer", @@ -95,7 +96,7 @@ func (Room) Init(cmd *cobra.Command) error { // Traefik - cmd.PersistentFlags().String("traefik.domain", "neko.lan", "traefik: domain on which will be container hosted") + cmd.PersistentFlags().String("traefik.domain", "", "traefik: domain on which will be container hosted (if empty or '*', match all; for neko-rooms as subdomain use '*.domain.tld')") if err := viper.BindPFlag("traefik.domain", cmd.PersistentFlags().Lookup("traefik.domain")); err != nil { return err } diff --git a/internal/room/manager.go b/internal/room/manager.go index f7a041d..8106bf8 100644 --- a/internal/room/manager.go +++ b/internal/room/manager.go @@ -148,11 +148,28 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro containerName := manager.config.InstanceName + "-" + roomName + // create traefik rule + traefikRule := "PathPrefix(`/" + roomName + "`)" + if manager.config.TraefikDomain != "" && manager.config.TraefikDomain != "*" { + // match *.domain.tld as subdomain + if strings.HasPrefix(manager.config.TraefikDomain, "*.") { + traefikRule = fmt.Sprintf( + "Host(`%s.%s`)", + roomName, + strings.TrimPrefix(manager.config.TraefikDomain, "*."), + ) + } else { + traefikRule += " && Host(`" + manager.config.TraefikDomain + "`)" + } + } else { + traefikRule += " && HostRegexp(`{host:.+}`)" + } + traefikLabels := map[string]string{ "traefik.enable": "true", "traefik.http.services." + containerName + "-frontend.loadbalancer.server.port": fmt.Sprintf("%d", frontendPort), "traefik.http.routers." + containerName + ".entrypoints": manager.config.TraefikEntrypoint, - "traefik.http.routers." + containerName + ".rule": "Host(`" + manager.config.TraefikDomain + "`) && PathPrefix(`/" + roomName + "`)", + "traefik.http.routers." + containerName + ".rule": traefikRule, "traefik.http.middlewares." + containerName + "-rdr.redirectregex.regex": "/" + roomName + "$$", "traefik.http.middlewares." + containerName + "-rdr.redirectregex.replacement": "/" + roomName + "/", "traefik.http.middlewares." + containerName + "-prf.stripprefix.prefixes": "/" + roomName + "/", @@ -170,6 +187,7 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro // instanceUrl := manager.config.InstanceUrl + instanceSuffix := roomName + "/" if instanceUrl == "" { urlProto := "http" if manager.config.TraefikCertresolver != "" { @@ -182,7 +200,18 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro port = ":" + manager.config.TraefikPort } - instanceUrl = urlProto + "://" + manager.config.TraefikDomain + port + "/" + if manager.config.TraefikDomain != "" && manager.config.TraefikDomain != "*" { + // match *.domain.tld as subdomain + if strings.HasPrefix(manager.config.TraefikDomain, "*.") { + instanceUrl = urlProto + "://" + roomName + "." + strings.TrimPrefix(manager.config.TraefikDomain, "*.") + port + "/" + instanceSuffix = "" + } else { + instanceUrl = urlProto + "://" + manager.config.TraefikDomain + port + "/" + } + } else { + // domain is not known + instanceUrl = urlProto + "://127.0.0.1" + port + "/" + } } else if !strings.HasSuffix(instanceUrl, "/") { instanceUrl = instanceUrl + "/" } @@ -197,7 +226,7 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro labels := manager.serializeLabels(RoomLabels{ Name: roomName, - URL: instanceUrl + roomName + "/", + URL: instanceUrl + instanceSuffix, Epr: epr, NekoImage: settings.NekoImage,