Compare commits

..

No commits in common. "master" and "v3.0.0-beta.12" have entirely different histories.

174 changed files with 1398 additions and 2710 deletions

View file

@ -1,21 +1,17 @@
name: Build Client
name: Build and Publish Client Artifacts
on:
workflow_call:
inputs:
with-artifact:
required: false
type: boolean
default: true
description: |
If true, the build artifacts will be uploaded as a GitHub Actions artifact.
This is useful for debugging and testing purposes. If false, the artifacts
will not be uploaded. This is useful for test builds where you don't need
the artifacts.
#pull_request: # Change to push when ready to deploy
# branches:
# - master
# paths:
# - client/**
# - .github/workflows/client_build.yml
jobs:
build-client:
name: Build Client
client_build:
name: Build and Publish Client Artifacts
runs-on: ubuntu-latest
steps:
@ -39,7 +35,6 @@ jobs:
- name: Upload artifacts
uses: actions/upload-artifact@v4
if: ${{ inputs.with-artifact }}
with:
name: client
path: client/dist

View file

@ -1,4 +1,4 @@
name: Test Client
name: Test Client Build
on:
pull_request:
@ -6,14 +6,28 @@ on:
- master
paths:
- client/**
- .github/workflows/client_build.yml
- .github/workflows/client_test.yml
jobs:
test-client:
name: Test Client
uses: ./.github/workflows/client_build.yml
with:
# Do not upload artifacts for test builds
with-artifact: false
secrets: inherit
client_test:
name: Test Client Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
cache-dependency-path: client/package-lock.json
- name: Install dependencies
working-directory: ./client
run: npm ci
- name: Build client
working-directory: ./client
run: npm run build

View file

@ -1,11 +1,8 @@
name: Build and Push to Docker Hub
name: "build and push amd64 images to Docker Hub"
on:
push:
branches:
- master
paths-ignore:
- 'webpage/**'
branches: [ master ]
#
# Run this action periodically to keep browsers up-to-date
# even if there is no activity in this repo.
@ -13,119 +10,68 @@ on:
schedule:
- cron: "43 2 * * 1"
# allow only one workflow to run at a time
# and cancel in-progress jobs if a new one is triggered
concurrency:
group: "dockerhub"
cancel-in-progress: true
env:
DOCKER_IMAGE: m1k1o/neko
jobs:
build-base:
name: Base Image
runs-on: ubuntu-latest
#
# do not run on forks
#
if: github.repository_owner == 'm1k1o'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Extract metadata (tags, labels) for Docker
uses: docker/metadata-action@v5
id: meta
with:
images: ${{ env.DOCKER_IMAGE }}
tags: |
type=raw,value=base
- name: Check Out Repo
uses: actions/checkout@v2
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ github.actor }}
password: ${{ secrets.DOCKER_TOKEN }}
run: |
docker login --username "${DOCKER_USERNAME}" --password-stdin "${DOCKER_REGISTRY}" <<< "${DOCKER_TOKEN}"
env:
DOCKER_REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
- name: Generate base Dockerfile
run: go run utils/docker/main.go -i Dockerfile.tmpl -o Dockerfile
- name: Build base
run: |
./build -b ${DOCKER_IMAGE}:base
docker push ${DOCKER_IMAGE}:base
- name: Build and push
uses: docker/build-push-action@v6
with:
context: ./
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-app:
name: App Image
build:
runs-on: ubuntu-latest
#
# do not run on forks
#
if: github.repository_owner == 'm1k1o'
needs: build-base
needs: [ build-base ]
strategy:
# Will build all images even if some fail.
fail-fast: false
matrix:
tag:
- firefox
# Temporarily disabled due to Cloudflare blocked download link
#- waterfox
- chromium
- google-chrome
- ungoogled-chromium
- microsoft-edge
- brave
- vivaldi
- opera
- tor-browser
- remmina
- vlc
- xfce
- kde
tags: [ firefox, waterfox, chromium, google-chrome, ungoogled-chromium, microsoft-edge, brave, vivaldi, opera, tor-browser, remmina, vlc, xfce, kde ]
env:
DOCKER_TAG: ${{ matrix.tags }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Extract metadata (tags, labels) for Docker
uses: docker/metadata-action@v5
id: meta
with:
images: ${{ env.DOCKER_IMAGE }}
tags: |
type=raw,value=latest,enable=${{ matrix.tag == 'firefox' }}
type=raw,value=${{ matrix.tag }}
- name: Check Out Repo
uses: actions/checkout@v2
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ github.actor }}
password: ${{ secrets.DOCKER_TOKEN }}
run: |
docker login --username "${DOCKER_USERNAME}" --password-stdin "${DOCKER_REGISTRY}" <<< "${DOCKER_TOKEN}"
env:
DOCKER_REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: apps/${{ matrix.tag }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
BASE_IMAGE=${{ env.DOCKER_IMAGE }}:base
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build container
run: |
./build -b ${DOCKER_IMAGE}:base -i ${DOCKER_IMAGE}
docker tag ${DOCKER_IMAGE}/${DOCKER_TAG} ${DOCKER_IMAGE}:${DOCKER_TAG}
docker push ${DOCKER_IMAGE}:${DOCKER_TAG}
- name: Push latest tag
if: ${{ matrix.tags == 'firefox' }}
run: |
docker pull ${DOCKER_IMAGE}:${DOCKER_TAG}
docker tag ${DOCKER_IMAGE}:${DOCKER_TAG} ${DOCKER_IMAGE}:latest
docker push ${DOCKER_IMAGE}:latest

View file

@ -1,57 +0,0 @@
name: Build and Push to GHCR
on:
push:
tags:
- 'v*'
jobs:
build-base:
name: Base Image
uses: ./.github/workflows/image_base.yml
with:
platforms: linux/amd64,linux/arm64,linux/arm/v7
secrets: inherit
build-app:
name: App Image
uses: ./.github/workflows/image_app.yml
needs: build-base
strategy:
# Will build all images even if some fail.
fail-fast: false
matrix:
include:
- name: firefox
platforms: linux/amd64,linux/arm64,linux/arm/v7
# Temporarily disabled due to Cloudflare blocked download link
#- name: waterfox
# platforms: linux/amd64
- name: chromium
platforms: linux/amd64,linux/arm64,linux/arm/v7
- name: google-chrome
platforms: linux/amd64
- name: ungoogled-chromium
platforms: linux/amd64
- name: microsoft-edge
platforms: linux/amd64
- name: brave
platforms: linux/amd64,linux/arm64
- name: vivaldi
platforms: linux/amd64,linux/arm64,linux/arm/v7
- name: opera
platforms: linux/amd64
- name: tor-browser
platforms: linux/amd64
- name: remmina
platforms: linux/amd64,linux/arm64,linux/arm/v7
- name: vlc
platforms: linux/amd64,linux/arm64,linux/arm/v7
- name: xfce
platforms: linux/amd64,linux/arm64,linux/arm/v7
- name: kde
platforms: linux/amd64,linux/arm64,linux/arm/v7
with:
name: ${{ matrix.name }}
platforms: ${{ matrix.platforms }}
secrets: inherit

44
.github/workflows/ghcr_amd64.yml vendored Normal file
View file

@ -0,0 +1,44 @@
name: "amd64 images"
on:
push:
tags:
- 'v*'
jobs:
build-base:
uses: ./.github/workflows/image_base.yml
with:
platforms: linux/amd64
dockerfile: Dockerfile
secrets:
GHCR_ACCESS_TOKEN: ${{ secrets.GHCR_ACCESS_TOKEN }}
build-apps:
uses: ./.github/workflows/image_app.yml
needs: [ build-base ]
strategy:
# Will build all images even if some fail.
fail-fast: false
matrix:
include:
- name: firefox
- name: waterfox
- name: chromium
- name: google-chrome
- name: ungoogled-chromium
- name: microsoft-edge
- name: brave
- name: vivaldi
- name: opera
- name: tor-browser
- name: remmina
- name: vlc
- name: xfce
- name: kde
with:
name: ${{ matrix.name }}
dockerfile: ${{ matrix.dockerfile }}
platforms: linux/amd64
secrets:
GHCR_ACCESS_TOKEN: ${{ secrets.GHCR_ACCESS_TOKEN }}

36
.github/workflows/ghcr_arm.yml vendored Normal file
View file

@ -0,0 +1,36 @@
name: "arm64v8 and arm32v7 images"
on:
push:
tags:
- 'v*'
jobs:
build-base:
uses: ./.github/workflows/image_base.yml
with:
flavor: arm
platforms: linux/arm64,linux/arm/v7
dockerfile: Dockerfile
secrets:
GHCR_ACCESS_TOKEN: ${{ secrets.GHCR_ACCESS_TOKEN }}
build-apps:
uses: ./.github/workflows/image_app.yml
needs: [ build-base ]
strategy:
# Will build all images even if some fail.
fail-fast: false
matrix:
include:
- name: firefox
- name: chromium
- name: vlc
- name: xfce
with:
name: ${{ matrix.name }}
dockerfile: ${{ matrix.dockerfile }}
flavor: arm
platforms: linux/arm64,linux/arm/v7
secrets:
GHCR_ACCESS_TOKEN: ${{ secrets.GHCR_ACCESS_TOKEN }}

View file

@ -1,4 +1,4 @@
name: Build and Push to GHCR for Intel
name: "intel gpu supported images"
on:
push:
@ -7,26 +7,24 @@ on:
jobs:
build-base:
name: Base Image
uses: ./.github/workflows/image_base.yml
with:
flavor: intel
platforms: linux/amd64
dockerfile: Dockerfile.intel
secrets: inherit
secrets:
GHCR_ACCESS_TOKEN: ${{ secrets.GHCR_ACCESS_TOKEN }}
build-app:
name: App Image
build-apps:
uses: ./.github/workflows/image_app.yml
needs: build-base
needs: [ build-base ]
strategy:
# Will build all images even if some fail.
fail-fast: false
matrix:
include:
- name: firefox
# Temporarily disabled due to Cloudflare blocked download link
#- name: waterfox
- name: waterfox
- name: chromium
- name: google-chrome
- name: ungoogled-chromium
@ -41,7 +39,8 @@ jobs:
- name: kde
with:
name: ${{ matrix.name }}
flavor: intel
platforms: ${{ matrix.platforms }}
dockerfile: ${{ matrix.dockerfile }}
secrets: inherit
flavor: intel
platforms: linux/amd64
secrets:
GHCR_ACCESS_TOKEN: ${{ secrets.GHCR_ACCESS_TOKEN }}

View file

@ -1,4 +1,4 @@
name: Build and Push to GHCR for Nvidia
name: "nvidia gpu supported images"
on:
push:
@ -7,18 +7,17 @@ on:
jobs:
build-base:
name: Base Image
uses: ./.github/workflows/image_base.yml
with:
flavor: nvidia
platforms: linux/amd64
dockerfile: Dockerfile.nvidia
secrets: inherit
secrets:
GHCR_ACCESS_TOKEN: ${{ secrets.GHCR_ACCESS_TOKEN }}
build-app:
name: App Image
build-apps:
uses: ./.github/workflows/image_app.yml
needs: build-base
needs: [ build-base ]
strategy:
# Will build all images even if some fail.
fail-fast: false
@ -36,7 +35,8 @@ jobs:
dockerfile: Dockerfile.nvidia
with:
name: ${{ matrix.name }}
flavor: nvidia
platforms: ${{ matrix.platforms }}
dockerfile: ${{ matrix.dockerfile }}
secrets: inherit
flavor: nvidia
platforms: linux/amd64
secrets:
GHCR_ACCESS_TOKEN: ${{ secrets.GHCR_ACCESS_TOKEN }}

View file

@ -1,4 +1,4 @@
name: Build App Image
name: Build and Publish Application Image
on:
workflow_call:
@ -6,7 +6,12 @@ on:
name:
required: true
type: string
description: "The name of the app to build."
description: "The name of the application to build."
dockerfile:
required: false
type: string
default: "Dockerfile"
description: "The Dockerfile to use for building the image."
flavor:
required: false
type: string
@ -17,18 +22,17 @@ on:
type: string
default: "linux/amd64"
description: "The platforms to build for."
dockerfile:
required: false
type: string
default: "Dockerfile"
description: "The Dockerfile to use for building the image."
secrets:
GHCR_ACCESS_TOKEN:
required: true
description: "GitHub Container Registry access token."
env:
FLAVOR_PREFIX: ${{ inputs.flavor && format('{0}-', inputs.flavor) || '' }}
jobs:
build-app:
name: Build App Image
name: Build and Publish Application Image
runs-on: ubuntu-latest
steps:
- name: Checkout
@ -48,7 +52,6 @@ jobs:
with:
images: ghcr.io/${{ github.repository }}/${{ env.FLAVOR_PREFIX }}${{ inputs.name }}
tags: |
type=edge,branch=master
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
@ -72,5 +75,3 @@ jobs:
build-args: |
BASE_IMAGE=ghcr.io/${{ github.repository }}/${{ env.FLAVOR_PREFIX }}base:sha-${{ github.sha }}
platforms: ${{ inputs.platforms || 'linux/amd64' }}
cache-from: type=gha
cache-to: type=gha,mode=max

View file

@ -1,8 +1,13 @@
name: Build Base Image
name: Build and Publish Base Image
on:
workflow_call:
inputs:
dockerfile:
required: false
type: string
default: "Dockerfile"
description: "The Dockerfile to use for building the image."
flavor:
required: false
type: string
@ -13,24 +18,22 @@ on:
type: string
default: "linux/amd64"
description: "The platforms to build for."
dockerfile:
required: false
type: string
default: "Dockerfile"
description: "The Dockerfile to use for building the image."
secrets:
GHCR_ACCESS_TOKEN:
required: true
description: "GitHub Container Registry access token."
env:
FLAVOR_PREFIX: ${{ inputs.flavor && format('{0}-', inputs.flavor) || '' }}
jobs:
build-client:
name: Build Client Artifacts
uses: ./.github/workflows/client_build.yml
build-base:
name: Build Base Image
name: Build and Publish Base Image
runs-on: ubuntu-latest
needs: build-client
needs: [ build-client ]
steps:
- name: Checkout
uses: actions/checkout@v4
@ -55,7 +58,6 @@ jobs:
with:
images: ghcr.io/${{ github.repository }}/${{ env.FLAVOR_PREFIX }}base
tags: |
type=edge,branch=master
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
@ -71,7 +73,7 @@ jobs:
- name: Generate base Dockerfile
env:
RUNTIME_DOCKERFILE: ${{ inputs.dockerfile || 'Dockerfile' }}
run: go run utils/docker/main.go -i Dockerfile.tmpl -o Dockerfile -client client/dist
run: go run docker/main.go -i Dockerfile.tmpl -o Dockerfile -client client/dist
- name: Build and push
uses: docker/build-push-action@v6
@ -81,5 +83,3 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: ${{ inputs.platforms || 'linux/amd64' }}
cache-from: type=gha
cache-to: type=gha,mode=max

65
.github/workflows/server_build.yml vendored Normal file
View file

@ -0,0 +1,65 @@
name: Build and Publish Server Artifacts
on:
workflow_call:
#pull_request: # Change to push when ready to deploy
# branches:
# - master
# paths:
# - server/**
# - .github/workflows/server_build.yml
jobs:
server_build:
name: Build and Publish Server Artifacts
runs-on: ubuntu-latest
strategy:
matrix:
variant:
- name: server-amd64
platform: linux/amd64
dockerfile: Dockerfile
- name: server-arm64
platform: linux/arm64
dockerfile: Dockerfile.bookworm
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
# Temporary hotfix for the setup-qemu-action
# Ref: https://github.com/tonistiigi/binfmt/issues/240
with:
platforms: linux/amd64,linux/arm64
image: tonistiigi/binfmt:qemu-v7.0.0-28
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Docker image
id: build
uses: docker/build-push-action@v6
with:
context: ./server/
file: ./server/${{ matrix.variant.dockerfile }}
tags: ${{ matrix.variant.name }}
platforms: ${{ matrix.variant.platform }}
load: true
- name: Copy artifacts
run: |
container_id=$(docker create ${{ matrix.variant.name }})
mkdir -p artifacts/${{ matrix.variant.name }}
docker cp $container_id:/src/bin/. artifacts/${{ matrix.variant.name }}/
docker rm $container_id
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.variant.name }}
path: artifacts/${{ matrix.variant.name }}

View file

@ -1,4 +1,4 @@
name: Test Server
name: Test Server Build
on:
pull_request:
@ -9,8 +9,8 @@ on:
- .github/workflows/server_test.yml
jobs:
build-amd64:
name: Build amd64
server_test:
name: Test Server Build
runs-on: ubuntu-latest
permissions:
contents: read
@ -24,21 +24,3 @@ jobs:
uses: docker/build-push-action@v6
with:
context: ./server
platforms: linux/amd64
build-arm64:
name: Build arm64
runs-on: ubuntu-24.04-arm
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build Docker image
uses: docker/build-push-action@v6
with:
context: ./server
platforms: linux/arm64

View file

@ -1,45 +0,0 @@
name: Build Webpage
on:
workflow_call:
inputs:
with-artifact:
required: false
type: boolean
default: true
description: |
If true, the build artifacts will be uploaded as a GitHub Actions artifact.
This is useful for debugging and testing purposes. If false, the artifacts
will not be uploaded. This is useful for test builds where you don't need
the artifacts.
jobs:
build-webpage:
name: Build Webpage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
cache-dependency-path: webpage/package-lock.json
- name: Install dependencies
working-directory: ./webpage
run: npm ci
- name: Build webpage
working-directory: ./webpage
run: npm run build
- if: ${{ inputs.with-artifact }}
name: Upload artifacts
uses: actions/upload-pages-artifact@v3
with:
artifact-name: github-pages
path: ./webpage/build

View file

@ -1,39 +1,50 @@
name: Build and Deploy Webpage to GitHub Pages
on:
# Runs on pushes targeting the default branch
push:
branches:
- master
paths:
- webpage/**
- .github/workflows/webpage_build.yml
- .github/workflows/webpage_deploy.yml
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
build-webpage:
name: Build Webpage
uses: ./.github/workflows/webpage_build.yml
secrets: inherit
webpage_build:
name: Build and Deploy Webpage to GitHub Pages
runs-on: ubuntu-latest
deploy-webpage:
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
cache-dependency-path: webpage/package-lock.json
- name: Install dependencies
working-directory: ./webpage
run: npm ci
- name: Build webpage
working-directory: ./webpage
run: npm run build
- name: Upload Build Artifact
uses: actions/upload-pages-artifact@v3
with:
artifact-name: github-pages
path: ./webpage/build
webpage_deploy:
name: Deploy to GitHub Pages
needs: build-webpage
needs: webpage_build
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
permissions:
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source
# Deploy to the github-pages environment
environment:

View file

@ -1,4 +1,4 @@
name: Test Webpage
name: Test Webpage Build
on:
pull_request:
@ -6,14 +6,26 @@ on:
- master
paths:
- webpage/**
- .github/workflows/webpage_build.yml
- .github/workflows/webpage_test.yml
jobs:
test-webpage:
name: Test Webpage
uses: ./.github/workflows/webpage_build.yml
with:
# Do not upload artifacts for test builds
with-artifact: false
secrets: inherit
webpage_test:
name: Test Webpage Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
cache-dependency-path: webpage/package-lock.json
- name: Install dependencies
working-directory: ./webpage
run: npm ci
- name: Build webpage
working-directory: ./webpage
run: npm run build

View file

@ -1,17 +1,14 @@
# This Dockerfile is pre-processed by the ./utils/docker script, it is not meant to be used directly.
# This Dockerfile is pre-processed by the ./docker script, it is not meant to be used directly.
FROM ./runtime/xorg-deps/ AS xorg-deps
FROM ./server/ AS server
FROM ./client/ AS client
FROM ./utils/xorg-deps/ AS xorg-deps
FROM ./runtime/$RUNTIME_DOCKERFILE AS runtime
# tells neko-rooms which version of the API to use
LABEL net.m1k1o.neko.api-version=3
COPY --from=xorg-deps /usr/local/lib/xorg/modules/drivers/dummy_drv.so /usr/lib/xorg/modules/drivers/dummy_drv.so
COPY --from=xorg-deps /usr/local/lib/xorg/modules/input/neko_drv.so /usr/lib/xorg/modules/input/neko_drv.so
COPY --from=server /src/bin/plugins/ /etc/neko/plugins/
COPY --from=server /src/bin/neko /usr/bin/neko
COPY --from=client /src/dist/ /var/www
COPY --from=xorg-deps /usr/local/lib/xorg/modules/drivers/dummy_drv.so /usr/lib/xorg/modules/drivers/dummy_drv.so
COPY --from=xorg-deps /usr/local/lib/xorg/modules/input/neko_drv.so /usr/lib/xorg/modules/input/neko_drv.so
COPY config.yml /etc/neko/neko.yaml

118
README.md
View file

@ -1,6 +1,6 @@
<div align="center">
<a href="https://github.com/m1k1o/neko" title="Neko's Github repository.">
<img src="https://neko.m1k1o.net/img/logo.png" width="400" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/logo.png" width="400" height="auto"/>
</a>
<p align="center">
<a href="https://github.com/m1k1o/neko/releases">
@ -21,14 +21,11 @@
<a href="https://discord.gg/3U6hWpC">
<img src="https://discordapp.com/api/guilds/665851821906067466/widget.png" alt="Chat on discord">
</a>
<a href="https://hellogithub.com/repository/4536d4546af24196af3f08a023dfa007" target="_blank">
<img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=4536d4546af24196af3f08a023dfa007&claim_uid=0x19e4dJwD83aW2&theme=small" alt="FeaturedHelloGitHub" />
</a>
<a href="https://github.com/m1k1o/neko/actions">
<img src="https://github.com/m1k1o/neko/actions/workflows/ghcr.yml/badge.svg" alt="build">
<img src="https://github.com/m1k1o/neko/actions/workflows/ghcr-amd.yml/badge.svg" alt="build">
</a>
</p>
<img src="https://neko.m1k1o.net/img/intro.gif" width="650" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/intro.gif" width="650" height="auto"/>
</div>
# n.eko
@ -86,60 +83,47 @@ Compared to clientless remote desktop gateway (e.g. [Apache Guacamole](https://g
### Supported browsers
<div align="center">
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#firefox">
<img src="https://neko.m1k1o.net/img/icons/firefox.svg" title="ghcr.io/m1k1o/neko/firefox" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#tor-browser">
<img src="https://neko.m1k1o.net/img/icons/tor-browser.svg" title="ghcr.io/m1k1o/neko/tor-browser" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#waterfox">
<img src="https://neko.m1k1o.net/img/icons/waterfox.svg" title="ghcr.io/m1k1o/neko/waterfox" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#chromium">
<img src="https://neko.m1k1o.net/img/icons/chromium.svg" title="ghcr.io/m1k1o/neko/chromium" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#google-chrome">
<img src="https://neko.m1k1o.net/img/icons/google-chrome.svg" title="ghcr.io/m1k1o/neko/google-chrome" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#ungoogled-chromium">
<img src="https://neko.m1k1o.net/img/icons/ungoogled-chromium.svg" title="ghcr.io/m1k1o/neko/google-chrome" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#microsoft-edge">
<img src="https://neko.m1k1o.net/img/icons/microsoft-edge.svg" title="ghcr.io/m1k1o/neko/microsoft-edge" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#brave">
<img src="https://neko.m1k1o.net/img/icons/brave.svg" title="ghcr.io/m1k1o/neko/brave" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#vivaldi">
<img src="https://neko.m1k1o.net/img/icons/vivaldi.svg" title="ghcr.io/m1k1o/neko/vivaldi" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#opera">
<img src="https://neko.m1k1o.net/img/icons/opera.svg" title="ghcr.io/m1k1o/neko/opera" width="60" height="auto"/>
</a>
... see [all available images](https://neko.m1k1o.net/docs/v3/installation/docker-images)
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/firefox.svg" title="m1k1o/neko:firefox" width="60" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/google-chrome.svg" title="m1k1o/neko:google-chrome" width="60" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/chromium.svg" title="m1k1o/neko:chromium" width="60" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/microsoft-edge.svg" title="m1k1o/neko:microsoft-edge" width="60" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/brave.svg" title="m1k1o/neko:brave" width="60" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/vivaldi.svg" title="m1k1o/neko:vivaldi" width="60" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/opera.svg" title="m1k1o/neko:opera" width="60" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/tor-browser.svg" title="m1k1o/neko:tor-browser" width="60" height="auto"/>
</div>
### Other applications
### Other programs
<div align="center">
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#xfce">
<img src="https://neko.m1k1o.net/img/icons/xfce.svg" title="ghcr.io/m1k1o/neko/xfce" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#kde">
<img src="https://neko.m1k1o.net/img/icons/kde.svg" title="ghcr.io/m1k1o/neko/kde" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#remmina">
<img src="https://neko.m1k1o.net/img/icons/remmina.svg" title="ghcr.io/m1k1o/neko/remmina" width="60" height="auto"/>
</a>
<a href="https://neko.m1k1o.net/docs/v3/installation/docker-images#vlc">
<img src="https://neko.m1k1o.net/img/icons/vlc.svg" title="ghcr.io/m1k1o/neko/vlc" width="60" height="auto"/>
</a>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/remmina.png" title="m1k1o/neko:remmina" width="60" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/vlc.svg" title="m1k1o/neko:vlc" width="60" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/xfce.svg" title="m1k1o/neko:xfce" width="60" height="auto"/>
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/icons/kde.svg" title="m1k1o/neko:kde" width="60" height="auto"/>
... others in <a href="https://github.com/m1k1o/neko-apps">m1k1o/neko-apps</a>
</div>
### Why neko?
### Features
* Text Chat (With basic markdown support, discord flavor)
* Admin users (Kick, Ban & Force Give/Release Controls, Lock room)
* Clipboard synchronization (on [supported browsers](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText))
* Emote overlay
* Ignore user (chat and emotes)
* Persistent settings
* Automatic Login with custom url args. (add `?usr=<your-user-name>&pwd=<room-pass>` to the url.)
* Broadcasting room content using RTMP (to e.g. twitch or youtube...)
* Bidirectional file transfer (if enabled)
<div align="center">
With `NEKO_FILE_TRANSFER_ENABLED=true`:
<img src="https://raw.githubusercontent.com/m1k1o/neko/master/docs/_media/file-transfer.gif" width="650" height="auto"/>
</div>
### Why n.eko?
I like cats 🐱 (`Neko` is the Japanese word for cat), I'm a weeb/nerd.
@ -147,26 +131,28 @@ I like cats 🐱 (`Neko` is the Japanese word for cat), I'm a weeb/nerd.
## Multiple rooms
For neko room management software, visit [neko-rooms](https://github.com/m1k1o/neko-rooms).
For n.eko room management software, visit [neko-rooms](https://github.com/m1k1o/neko-rooms).
It also offers [Zero-knowledge installation (with HTTPS)](https://github.com/m1k1o/neko-rooms/?tab=readme-ov-file#zero-knowledge-installation-with-https).
It also offers zero-knowledge [installation script (with HTTPS and Traefik)](https://github.com/m1k1o/neko-rooms/#zero-knowledge-installation-with-https-and-traefik).
## Documentation
Full documentation is available at [neko.m1k1o.net](https://neko.m1k1o.net/). Key sections include:
* [Getting Started](https://neko.m1k1o.net/#/getting-started/)
* [Quick Start](https://neko.m1k1o.net/#/getting-started/quick-start)
* [Examples](https://neko.m1k1o.net/#/getting-started/examples)
* [Reverse Proxy](https://neko.m1k1o.net/#/getting-started/reverse-proxy)
* [Configuration](https://neko.m1k1o.net/#/getting-started/configuration)
* [Troubleshooting](https://neko.m1k1o.net/#/getting-started/troubleshooting)
* [Mobile Support](https://neko.m1k1o.net/#/mobile-support)
* [Contributing](https://neko.m1k1o.net/#/contributing)
* [Non Goals](https://neko.m1k1o.net/#/non-goals)
* [Technologies](https://neko.m1k1o.net/#/technologies)
* [Changelog](https://neko.m1k1o.net/#/changelog)
- [Migration from V2](https://neko.m1k1o.net/docs/v3/migration-from-v2)
- [Getting Started](https://neko.m1k1o.net/docs/v3/quick-start)
- [Installation](https://neko.m1k1o.net/docs/v3/installation)
- [Examples](https://neko.m1k1o.net/docs/v3/installation/examples)
- [Configuration](https://neko.m1k1o.net/docs/v3/configuration)
- [Frequently Asked Questions](https://neko.m1k1o.net/docs/v3/faq)
- [Troubleshooting](https://neko.m1k1o.net/docs/v3/troubleshooting)
## How to contribute? How to build?
## How to Contribute
Contributions are welcome! Check the [Contributing Guide](https://neko.m1k1o.net/contributing) for details.
Navigate to [.docker](.docker) folder for further information.
## Support
If you find Neko useful, consider supporting the project via [GitHub Sponsors](https://github.com/sponsors/m1k1o).
If you want to support this project, you can do it [here](https://github.com/sponsors/m1k1o).

View file

@ -1,19 +0,0 @@
# Security Policy
## Reporting a Vulnerability
If there are any vulnerabilities in **m1k1o/neko**, don't hesitate to _report them_.
1. Send an email to `security@m1k1o.net`.
2. Describe the vulnerability.
If you have a fix, that is most welcome -- please attach or summarize it in your message!
3. We will evaluate the vulnerability and, if necessary, release a fix or mitigating steps to address it. We will contact you to let you know the outcome, and will credit you in the report.
Please **do not disclose the vulnerability publicly** until a fix is released!
4. Once we have either a) published a fix, or b) declined to address the vulnerability for whatever reason, you are free to publicly disclose it.
We appreciate your help in keeping Neko secure.

View file

@ -1,13 +1,12 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
RUN set -eux; apt-get update; \
apt-get install -y --no-install-recommends apt-transport-https curl openbox; \
#
# install brave browser
ARCH=$(dpkg --print-architecture); \
curl -fsSLo /usr/share/keyrings/brave-browser-archive-keyring.gpg https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg; \
echo "deb [signed-by=/usr/share/keyrings/brave-browser-archive-keyring.gpg arch=${ARCH}] https://brave-browser-apt-release.s3.brave.com/ stable main" \
echo "deb [signed-by=/usr/share/keyrings/brave-browser-archive-keyring.gpg arch=amd64] https://brave-browser-apt-release.s3.brave.com/ stable main" \
| tee /etc/apt/sources.list.d/brave-browser-release.list; \
apt-get update; \
apt-get install -y --no-install-recommends brave-browser; \

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/nvidia-base:latest
ARG BASE_IMAGE=m1k1o/neko:nvidia-base
FROM $BASE_IMAGE
RUN set -eux; apt-get update; \

View file

@ -12,11 +12,9 @@ command=/bin/entrypoint.sh /usr/bin/brave-browser
--enable-features=Vulkan,UseSkiaRenderer,VaapiVideoEncoder,VaapiVideoDecoder,CanvasOopRasterization
--ignore-gpu-blocklist
--disable-seccomp-filter-sandbox
--use-angle=vulkan
--use-gl=egl
--disable-software-rasterizer
--disable-dev-shm-usage
--disable-vulkan-surface
--enable-unsafe-webgpu
stopsignal=INT
autorestart=true
priority=800

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
#

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/nvidia-base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
#

View file

@ -12,11 +12,9 @@ command=/bin/entrypoint.sh /usr/bin/chromium
--enable-features=Vulkan,UseSkiaRenderer,VaapiVideoEncoder,VaapiVideoDecoder,CanvasOopRasterization
--ignore-gpu-blocklist
--disable-seccomp-filter-sandbox
--use-angle=vulkan
--use-gl=egl
--disable-software-rasterizer
--disable-dev-shm-usage
--disable-vulkan-surface
--enable-unsafe-webgpu
stopsignal=INT
autorestart=true
priority=800

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
#
@ -10,7 +10,7 @@ RUN set -eux; apt-get update; \
#
# install firefox-esr for armhf
apt-get install -y --no-install-recommends firefox-esr; \
ln -s /usr/lib/firefox-esr /usr/lib/firefox; \
ln -s /usr/bin/firefox-esr /usr/bin/firefox; \
#
# install extensions
mkdir -p /usr/lib/firefox-esr/distribution/extensions; \

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/nvidia-base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
ARG SRC_URL="https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US"

View file

@ -15,8 +15,8 @@ lockPref("plugins.hide_infobar_for_missing_plugin", true);
lockPref("profile.allow_automigration", false);
lockPref("signon.prefillForms", false);
lockPref("signon.rememberSignons", false);
//lockPref("xpinstall.enabled", false);
//lockPref("xpinstall.whitelist.required", true);
lockPref("xpinstall.enabled", false);
lockPref("xpinstall.whitelist.required", true);
lockPref("browser.download.manager.retention", 0);
lockPref("browser.download.folderList", 2);
lockPref("browser.download.forbid_open_with", true);

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
ARG SRC_URL="https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb"

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/nvidia-base:latest
ARG BASE_IMAGE=m1k1o/neko:nvidia-base
FROM $BASE_IMAGE
# latest working version with EGL: 111.0.5563.146, revert when resolved

View file

@ -12,11 +12,9 @@ command=/bin/entrypoint.sh /usr/bin/google-chrome
--enable-features=Vulkan,UseSkiaRenderer,VaapiVideoEncoder,VaapiVideoDecoder,CanvasOopRasterization
--ignore-gpu-blocklist
--disable-seccomp-filter-sandbox
--use-angle=vulkan
--use-gl=egl
--disable-software-rasterizer
--disable-dev-shm-usage
--disable-vulkan-surface
--enable-unsafe-webgpu
stopsignal=INT
autorestart=true
priority=800

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
#

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
ARG API_URL="https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-stable/"

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
ARG API_URL="https://packages.microsoft.com/repos/edge/pool/main/m/microsoft-edge-stable/"

View file

@ -12,11 +12,9 @@ command=/bin/entrypoint.sh /usr/bin/microsoft-edge
--enable-features=Vulkan,UseSkiaRenderer,VaapiVideoEncoder,VaapiVideoDecoder,CanvasOopRasterization
--ignore-gpu-blocklist
--disable-seccomp-filter-sandbox
--use-angle=vulkan
--use-gl=egl
--disable-software-rasterizer
--disable-dev-shm-usage
--disable-vulkan-surface
--enable-unsafe-webgpu
stopsignal=INT
autorestart=true
priority=800

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
ARG API_URL="https://download5.operacdn.com/pub/opera/desktop/"

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
# install remmina

View file

@ -1,4 +1,5 @@
#!/bin/bash
set -u
err() {
echo "ERROR: $*" >&2
@ -15,28 +16,23 @@ if [[ -n "$REMMINA_PROFILE" ]]; then
exec remmina -c "$profile"
fi
if [[ ! -z "$REMMINA_URL" ]]; then
readarray -t arr < <( echo -n "$REMMINA_URL" | perl -pe 's|^(\w+)\:\/\/(?:([^:]+)(?::([^@]+))?@)?(.*)$|\1\n\2\n\3\n\4|' )
proto="${arr[0]}"
user="${arr[1]}"
pw="${arr[2]}"
host="${arr[3]}"
echo "Parsed url in 'REMMINA_URL': proto:$proto username:$user host:$host"
[[ -z "$REMMINA_URL" ]] && err "Neither 'REMMINA_PROFILE' nor 'REMMINA_URL' found in env vars"
[[ "$proto" != "vnc" && "$proto" != "rdp" && "$proto" != "spice" ]] && err "Unsupported protocol $proto in connection url 'REMMINA_URL'"
readarray -t arr < <( echo -n "$REMMINA_URL" | perl -pe 's|^(\w+)\:\/\/(?:([^:]+)(?::([^@]+))?@)?(.*)$|\1\n\2\n\3\n\4|' )
proto="${arr[0]}"
user="${arr[1]}"
pw="${arr[2]}"
host="${arr[3]}"
echo "Parsed url in 'REMMINA_URL': proto:$proto username:$user host:$host"
profile="$profile_dir"/"$proto".remmina
remmina --set-option username="$user" --update-profile "$profile"
remmina --set-option password="$pw" --update-profile "$profile"
remmina --set-option server="$host" --update-profile "$profile"
[[ "$proto" != "vnc" && "$proto" != "rdp" && "$proto" != "spice" ]] && err "Unsupported protocol $proto in connection url 'REMMINA_URL'"
# remmina --set-option window_maximize=1 --update-profile "$profile"
# remmina --set-option scale=1 --update-profile "$profile"
profile="$profile_dir"/"$proto".remmina
remmina --set-option username="$user" --update-profile "$profile"
remmina --set-option password="$pw" --update-profile "$profile"
remmina --set-option server="$host" --update-profile "$profile"
echo "Running remmina with URL $REMMINA_URL"
exec remmina -c "$profile"
fi
# remmina --set-option window_maximize=1 --update-profile "$profile"
# remmina --set-option scale=1 --update-profile "$profile"
echo "Running remmina without connection profile"
exec remmina
exec remmina -c "$profile"

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
#

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
ARG API_URL="https://api.github.com/repos/macchrome/linchrome/releases/latest"

View file

@ -1,14 +1,17 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
ARG VIVALDI_VERSION="5.3.2679.34-1"
# TODO: Get chromium version from vivaldi
ARG CHROMIUM_VERSION="102.0.5005.72"
#
# install vivaldi
SHELL ["/bin/bash", "-c"]
RUN set -eux; apt-get update; \
ARCH=$(dpkg --print-architecture); \
wget -O /tmp/vivaldi.deb "https://downloads.vivaldi.com/stable/vivaldi-stable_${ARCH}.deb"; \
apt-get install -y --no-install-recommends wget unzip xz-utils jq openbox; \
apt install -y --no-install-recommends /tmp/vivaldi.deb; \
wget -O /tmp/vivaldi.deb "https://downloads.vivaldi.com/stable/vivaldi-stable_${VIVALDI_VERSION}_amd64.deb"; \
apt-get install -y --no-install-recommends wget unzip xz-utils jq openbox /tmp/vivaldi.deb; \
/opt/vivaldi/update-ffmpeg; \
#
# install latest version of uBlock Origin and SponsorBlock for YouTube
EXTENSIONS_DIR="/usr/share/chromium/extensions"; \
@ -19,7 +22,7 @@ RUN set -eux; apt-get update; \
mkdir -p "${EXTENSIONS_DIR}"; \
for EXT_ID in "${EXTENSIONS[@]}"; \
do \
EXT_URL="https://clients2.google.com/service/update2/crx?response=redirect&prodversion=100&acceptformat=crx2,crx3&x=id%3D${EXT_ID}%26installsource%3Dondemand%26uc"; \
EXT_URL="https://clients2.google.com/service/update2/crx?response=redirect&nacl_arch=x86-64&prodversion=${CHROMIUM_VERSION}&acceptformat=crx2,crx3&x=id%3D${EXT_ID}%26installsource%3Dondemand%26uc"; \
EXT_PATH="${EXTENSIONS_DIR}/${EXT_ID}.crx"; \
wget -O "${EXT_PATH}" "${EXT_URL}"; \
EXT_VERSION="$(unzip -p "${EXT_PATH}" manifest.json 2>/dev/null | jq -r ".version")"; \

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
#

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
ARG SRC_URL="https://cdn1.waterfox.net/waterfox/releases/latest/linux"
@ -10,7 +10,7 @@ RUN set -eux; apt-get update; \
xz-utils bzip2 libgtk-3-0 libdbus-glib-1-2; \
#
# fetch latest release
wget --user-agent="Mozilla/5.0" -O /tmp/waterfox-setup.tar.bz2 "${SRC_URL}"; \
wget -O /tmp/waterfox-setup.tar.bz2 "${SRC_URL}"; \
mkdir /usr/lib/waterfox; \
tar -xjf /tmp/waterfox-setup.tar.bz2 -C /usr/lib; \
rm -f /tmp/waterfox-setup.tar.bz2; \

View file

@ -15,8 +15,8 @@ lockPref("plugins.hide_infobar_for_missing_plugin", true);
lockPref("profile.allow_automigration", false);
lockPref("signon.prefillForms", false);
lockPref("signon.rememberSignons", false);
//lockPref("xpinstall.enabled", false);
//lockPref("xpinstall.whitelist.required", true);
lockPref("xpinstall.enabled", false);
lockPref("xpinstall.whitelist.required", true);
lockPref("browser.download.manager.retention", 0);
lockPref("browser.download.folderList", 2);
lockPref("browser.download.forbid_open_with", true);

View file

@ -1,4 +1,4 @@
ARG BASE_IMAGE=ghcr.io/m1k1o/neko/base:latest
ARG BASE_IMAGE=m1k1o/neko:base
FROM $BASE_IMAGE
#

98
build
View file

@ -2,57 +2,39 @@
set -e
cd "$(dirname "$0")"
#
# This script builds the neko base image and all the applications
#
# disable buildx because of https://github.com/docker/buildx/issues/847
# if you want to use buildx, set USE_BUILDX=1
if [ -z "$USE_BUILDX" ]; then
USE_BUILDX=0
fi
# check if docker buildx is available, its not docker-buildx command but rather subcommand of docker
#if [ -z "$USE_BUILDX" ] && [ -x "$(command -v docker)" ]; then
# if docker buildx version >/dev/null 2>&1; then
# USE_BUILDX=1
# fi
#fi
if [ -z "$USE_BUILDX" ] && [ -x "$(command -v docker)" ]; then
if docker buildx version >/dev/null 2>&1; then
USE_BUILDX=1
fi
fi
#
# This script builds the neko base image and all the applications
#
function log() {
echo "$(date +'%Y-%m-%d %H:%M:%S') - [NEKO] - $1" > /dev/stderr
}
function help() {
echo "Usage: $0 [options] [image]"
echo
echo "Options:"
echo " -p, --platform : The platform (default: system architecture)"
echo " -r, --repository : The repository prefix (default: ghcr.io/m1k1o/neko)"
echo " -t, --tag : The image tag, can be specified multiple times, if not specified"
echo " uses 'latest' and if available, current git semver tag (v*.*.*)"
echo " -f, --flavor : The flavor, if not specified, builds without flavor"
echo " -b, --base_image : The base image name (default: <repository>[<flavor>-]base:<tag>)"
echo " -a, --application : The app to build, if not specified, builds the base image"
echo " -y, --yes : Skip confirmation prompts"
echo " --no-cache : Build without docker cache"
echo " --push : Push the image to the registry after building"
echo " -h, --help : Show this help message"
echo
echo "Positional arguments:"
echo " <image> : The image name, if not specified, uses the full image name"
echo " in the format <repository>/<flavor>-<application>:<tag>"
echo " Example: ghcr.io/m1k1o/neko/nvidia-firefox:latest"
echo " You can override any of the above options by specifying them"
echo " after the image name."
echo
echo "Environment variables:"
echo " USE_BUILDX : Set to 1 to use docker buildx instead of docker build"
echo " (default: 0)"
echo " CLIENT_DIST : The client dist file to use, if not specified, builds them"
echo " from the source code."
echo " (options) : Options can be specified as environment variables, for example:"
echo " PLATFORM=linux/arm64 $0 --repository ghcr.io/m1k1o/neko"
echo "Usage: $0"
echo " -p, --platform : The platform (default: linux/amd64)"
echo " -r, --repository : The repository prefix (default: ghcr.io/m1k1o/neko)"
echo " -t, --tag : The image tag, can be specified multiple times, if not specified"
echo " uses 'latest' and if available, current git semver tag (v*.*.*)"
echo " -f, --flavor : The flavor, if not specified, builds without flavor"
echo " -b, --base : The base image name (default: <repository>[<flavor>-]base:<tag>)"
echo " -a, --app : The app to build, if not specified, builds the base image"
echo " -y, --yes : Skip confirmation prompts"
echo " --no-cache : Build without docker cache"
echo " --push : Push the image to the registry after building"
echo " -h, --help : Show this help message"
}
FULL_IMAGE=""
@ -62,8 +44,8 @@ while [[ "$#" -gt 0 ]]; do
--repository|-r) REPOSITORY="$2"; shift ;;
--tag|-t) TAGS+=("$2"); TAG="$2"; shift ;;
--flavor|-f) FLAVOR="$2"; shift ;;
--base_image|-b) BASE_IMAGE="$2"; shift ;;
--application|-a) APPLICATION="$2"; shift ;;
--base|-b) BASE_IMAGE="$2"; shift ;;
--app|-a) APPLICATION="$2"; shift ;;
--yes|-y) YES=1 ;;
--no-cache) NO_CACHE="--no-cache" log "Building without cache" ;;
--push) PUSH=1 ;;
@ -149,12 +131,17 @@ function build_image() {
local APPLICATION_IMAGE="$1"
shift
# get list of tags in full format: <image>:<tag>
local IMAGE_NO_TAG="${APPLICATION_IMAGE%:*}"
local FULL_TAGS=()
for T in "${TAGS[@]}"; do
FULL_TAGS+=("$IMAGE_NO_TAG:$T")
done
# if the image name starts with local/, just use the tag as is
if [[ "$APPLICATION_IMAGE" == *"local/"* ]]; then
FULL_TAGS=("$APPLICATION_IMAGE")
else
# get list of tags in full format: <image>:<tag>
local IMAGE_NO_TAG="${APPLICATION_IMAGE%:*}"
for T in "${TAGS[@]}"; do
FULL_TAGS+=("$IMAGE_NO_TAG:$T")
done
fi
if [ -z "$USE_BUILDX" ] || [ "$USE_BUILDX" != "1" ]; then
# if buildx is not available, use docker build
@ -210,18 +197,7 @@ else
fi
if [ -z "$PLATFORM" ]; then
# use system architecture if not specified
UNAME="$(uname -m)"
if [ "$UNAME" == "x86_64" ]; then
PLATFORM="linux/amd64"
elif [ "$UNAME" == "aarch64" ] || [ "$UNAME" == "arm64" ]; then
PLATFORM="linux/arm64"
elif [ "$UNAME" == "armv7l" ]; then
PLATFORM="linux/arm/v7"
else
log "Unknown architecture: $UNAME"
exit 1
fi
PLATFORM="linux/amd64"
fi
log "Using platform: $PLATFORM"
@ -314,10 +290,10 @@ fi
log "Building base image: $BASE_IMAGE"
docker run --rm -i \
-v "$(pwd)":/src \
-v ./:/src \
-e "RUNTIME_DOCKERFILE=$RUNTIME_DOCKERFILE" \
--workdir /src \
--entrypoint go \
golang:1.24-bullseye \
run utils/docker/main.go \
-i Dockerfile.tmpl -client "$CLIENT_DIST" | build_image $BASE_IMAGE -f - .
run ./docker/main.go \
-i Dockerfile.tmpl -client $CLIENT_DIST | build_image $BASE_IMAGE -f - .

View file

@ -119,43 +119,23 @@
}
}
@media only screen and (max-width: 1024px) {
html,
body {
overflow-y: auto !important;
width: auto !important;
height: auto !important;
}
body > p {
display: none;
}
#neko {
position: relative;
flex-direction: column;
max-height: initial !important;
@media only screen and (max-width: 600px) {
#neko.expanded {
.neko-main {
height: 100vh;
transform: translateX(calc(-100% + 65px));
video {
display: none;
}
}
.neko-menu {
height: 100vh;
width: 100% !important;
}
}
}
@media only screen and (max-width: 1024px) and (orientation: portrait) {
#neko {
&.expanded .neko-main {
height: 40vh;
}
&.expanded .neko-menu {
height: 60vh;
width: 100% !important;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 65px;
width: calc(100% - 65px);
}
}
}
@ -237,20 +217,6 @@
}
}
@Watch('side')
onSide(side: boolean) {
if (side) {
console.log('side enabled')
// scroll to the side
this.$nextTick(() => {
const side = document.querySelector('aside')
if (side) {
side.scrollIntoView({ behavior: 'smooth', block: 'start' })
}
})
}
}
controlAttempt() {
if (this.shakeKbd || this.$accessor.remote.hosted) return

View file

@ -24,7 +24,7 @@
<style lang="scss" scoped>
.connect {
position: fixed;
position: absolute;
top: 0;
left: 0;
right: 0;

View file

@ -60,9 +60,8 @@
</style>
<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator'
import { Component, Vue } from 'vue-property-decorator'
import { messages } from '~/locale'
import { set } from '~/utils/localstorage'
@Component({ name: 'neko-menu' })
export default class extends Vue {
@ -78,11 +77,6 @@
this.$accessor.client.toggleAbout()
}
@Watch('$i18n.locale')
onLanguageChange(newLang: string) {
set('lang', newLang)
}
mounted() {
const default_lang = new URL(location.href).searchParams.get('lang')
if (default_lang && this.langs.includes(default_lang)) {

View file

@ -40,12 +40,7 @@
<li v-if="admin"><i @click.stop.prevent="openResolution" class="fas fa-desktop"></i></li>
<li v-if="!controlLocked && !implicitHosting" :class="extraControls || 'extra-control'">
<i
:class="[
hosted && !hosting ? 'disabled' : '',
!hosted && !hosting ? 'faded' : '',
'fas',
'fa-computer-mouse',
]"
:class="[hosted && !hosting ? 'disabled' : '', !hosted && !hosting ? 'faded' : '', 'fas', 'fa-keyboard']"
@click.stop.prevent="toggleControl"
/>
</li>
@ -62,13 +57,6 @@
class="fas fa-external-link-alt"
/>
</li>
<li
v-if="hosting && is_touch_device"
:class="extraControls || 'extra-control'"
@click.stop.prevent="openMobileKeyboard"
>
<i class="fas fa-keyboard" />
</li>
</ul>
<neko-resolution ref="resolution" v-if="admin" />
<neko-clipboard ref="clipboard" v-if="hosting && (!clipboard_read_available || !clipboard_write_available)" />
@ -129,7 +117,7 @@
}
@media (max-width: 768px) {
&.extra-control {
display: block;
display: inline-block;
}
}
@ -263,10 +251,6 @@
return this.$accessor.connecting
}
get controlling() {
return this.$accessor.remote.controlling
}
get hosting() {
return this.$accessor.remote.hosting
}
@ -369,16 +353,6 @@
return this.$accessor.video.horizontal
}
get is_touch_device() {
return (
// detect if the device has touch support
('ontouchstart' in window || navigator.maxTouchPoints > 0) &&
// the primary input mechanism includes a pointing device of
// limited accuracy, such as a finger on a touchscreen.
window.matchMedia('(pointer: coarse)').matches
)
}
@Watch('width')
onWidthChanged() {
this.onResize()
@ -756,17 +730,12 @@
first.target.dispatchEvent(simulatedEvent)
}
isMouseDown = false
onMouseDown(e: MouseEvent) {
this.isMouseDown = true
if (this.locked) {
return
if (!this.hosting) {
this.$emit('control-attempt', e)
}
if (!this.controlling) {
this.implicitHostingRequest(e)
if (!this.hosting || this.locked) {
return
}
@ -775,16 +744,7 @@
}
onMouseUp(e: MouseEvent) {
// only if we are the one who started the mouse down
if (!this.isMouseDown) return
this.isMouseDown = false
if (this.locked) {
return
}
if (!this.controlling) {
this.implicitHostingRequest(e)
if (!this.hosting || this.locked) {
return
}
@ -792,40 +752,6 @@
this.$client.sendData('mouseup', { key: e.button + 1 })
}
private reqMouseDown: MouseEvent | null = null
private reqMouseUp: MouseEvent | null = null
@Watch('controlling')
onControlChange(controlling: boolean) {
if (controlling && this.reqMouseDown) {
this.onMouseDown(this.reqMouseDown)
}
if (controlling && this.reqMouseUp) {
this.onMouseUp(this.reqMouseUp)
}
this.reqMouseDown = null
this.reqMouseUp = null
}
implicitHostingRequest(e: MouseEvent) {
if (this.implicitHosting) {
if (e.type === 'mousedown') {
this.reqMouseDown = e
this.reqMouseUp = null
this.$accessor.remote.request()
} else if (e.type === 'mouseup') {
this.reqMouseUp = e
}
return
}
if (e.type === 'mousedown') {
this.$emit('control-attempt', e)
}
}
onMouseMove(e: MouseEvent) {
if (!this.hosting || this.locked) {
return
@ -873,20 +799,10 @@
@Watch('hosting')
@Watch('locked')
onFocus() {
// focus opens the keyboard on mobile
if (this.is_touch_device) {
return
}
// in order to capture key events, overlay must be focused
if (this.focused && this.hosting && !this.locked) {
this._overlay.focus()
}
}
openMobileKeyboard() {
// focus opens the keyboard on mobile
this._overlay.focus()
}
}
</script>

View file

@ -15,7 +15,7 @@ export const EVENT = {
ERROR: 'system/error',
},
CLIENT: {
HEARTBEAT: 'client/heartbeat',
HEARTBEAT: 'client/heartbeat'
},
SIGNAL: {
OFFER: 'signal/offer',

View file

@ -1,31 +1,11 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import { messages } from '~/locale'
import { get } from '~/utils/localstorage'
Vue.use(VueI18n)
const fallbackLocale = 'en'
function detectBrowserLanguage(): string {
const browserLang = navigator.language.toLowerCase()
const supportedLangs = Object.keys(messages)
if (supportedLangs.includes(browserLang)) {
return browserLang
}
const baseLang = browserLang.split('-')[0]
const matchingLang = supportedLangs.find((lang) => lang.startsWith(baseLang))
if (matchingLang) {
return matchingLang
}
return fallbackLocale
}
export const i18n = new VueI18n({
locale: get<string>('lang', detectBrowserLanguage()),
fallbackLocale,
locale: 'en',
fallbackLocale: 'en',
messages,
})

View file

@ -18,9 +18,6 @@ export const state = () => ({
})
export const getters = getterTree(state, {
controlling: (state, getters, root) => {
return root.user.id === state.id
},
hosting: (state, getters, root) => {
return root.user.id === state.id || state.implicitHosting
},
@ -92,7 +89,7 @@ export const actions = actionTree(
},
request({ getters }) {
if (!accessor.connected || getters.controlling) {
if (!accessor.connected || getters.hosting) {
return
}

View file

@ -15,3 +15,6 @@ session:
cookie:
# needed for legacy API
enabled: false
webrtc:
icelite: true

View file

@ -1,14 +1,15 @@
version: "3.4"
services:
neko:
image: "ghcr.io/m1k1o/neko/firefox:latest"
image: "m1k1o/neko:firefox"
restart: "unless-stopped"
shm_size: "2gb"
ports:
- "8080:8080"
- "52000-52100:52000-52100/udp"
environment:
NEKO_DESKTOP_SCREEN: 1920x1080@30
NEKO_MEMBER_MULTIUSER_USER_PASSWORD: neko
NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD: admin
NEKO_WEBRTC_EPR: 52000-52100
NEKO_WEBRTC_ICELITE: 1
NEKO_SCREEN: 1920x1080@30
NEKO_PASSWORD: neko
NEKO_PASSWORD_ADMIN: admin
NEKO_EPR: 52000-52100
NEKO_ICELITE: 1

3
docker/go.mod Normal file
View file

@ -0,0 +1,3 @@
module github.com/m1k1o/neko/docker
go 1.24.1

View file

@ -103,9 +103,7 @@ ENV NEKO_PLUGINS_DIR=/etc/neko/plugins/
#
# add healthcheck
HEALTHCHECK --interval=10s --timeout=5s --retries=8 \
CMD wget -O - http://localhost:${NEKO_SERVER_BIND#*:}/health || \
wget --no-check-certificate -O - https://localhost:${NEKO_SERVER_BIND#*:}/health || \
exit 1
CMD wget -O - http://localhost:${NEKO_SERVER_BIND#*:}/health || exit 1
#
# run neko

View file

@ -95,9 +95,8 @@ ENV NEKO_PLUGINS_DIR=/etc/neko/plugins/
#
# add healthcheck
HEALTHCHECK --interval=10s --timeout=5s --retries=8 \
CMD wget -O - http://localhost:${NEKO_SERVER_BIND#*:}/health || \
wget --no-check-certificate -O - https://localhost:${NEKO_SERVER_BIND#*:}/health || \
exit 1
CMD wget -O - http://localhost:${NEKO_SERVER_BIND#*:}/health || exit 1
#
# run neko
CMD ["/usr/bin/supervisord", "-c", "/etc/neko/supervisord.conf"]

View file

@ -115,9 +115,8 @@ ENV RENDER_GID=
#
# add healthcheck
HEALTHCHECK --interval=10s --timeout=5s --retries=8 \
CMD wget -O - http://localhost:${NEKO_SERVER_BIND#*:}/health || \
wget --no-check-certificate -O - https://localhost:${NEKO_SERVER_BIND#*:}/health || \
exit 1
CMD wget -O - http://localhost:${NEKO_SERVER_BIND#*:}/health || exit 1
#
# run neko
CMD ["/usr/bin/supervisord", "-c", "/etc/neko/supervisord.conf"]

View file

@ -1,6 +1,6 @@
ARG UBUNTU_RELEASE=20.04
ARG CUDA_VERSION=11.4.3
ARG VIRTUALGL_VERSION=3.1.3-20250409
ARG VIRTUALGL_VERSION=3.1
ARG GSTREAMER_VERSION=1.20
#
@ -61,13 +61,13 @@ ARG UBUNTU_RELEASE
ARG VIRTUALGL_VERSION
# Make all NVIDIA GPUs visible by default
ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_VISIBLE_DEVICES all
# All NVIDIA driver capabilities should preferably be used, check `NVIDIA_DRIVER_CAPABILITIES` inside the container if things do not work
ENV NVIDIA_DRIVER_CAPABILITIES=all
ENV NVIDIA_DRIVER_CAPABILITIES all
#
# set vgl-display to headless 3d gpu card/// correct values are egl[n] or /dev/dri/card0:if this is passed into container
ENV VGL_DISPLAY=egl
ENV VGL_DISPLAY egl
#
# set custom user
@ -205,22 +205,23 @@ RUN VULKAN_API_VERSION=$(dpkg -s libvulkan1 | grep -oP 'Version: [0-9|\.]+' | gr
}" > /etc/vulkan/icd.d/nvidia_icd.json
#
# install an up-to-date version of VirtualGL
RUN apt-get update; \
apt-get install -y --no-install-recommends wget gpg ca-certificates; \
# Add VirtualGL GPG key
wget -q -O- https://packagecloud.io/dcommander/virtualgl/gpgkey | \
gpg --dearmor >/etc/apt/trusted.gpg.d/VirtualGL.gpg; \
# Download the official VirtualGL.list file
wget -q -O /etc/apt/sources.list.d/VirtualGL.list \
https://raw.githubusercontent.com/VirtualGL/repo/main/VirtualGL.list; \
# Install packages
# install VirtualGL and make libraries available for preload
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends virtualgl=${VIRTUALGL_VERSION}; \
wget "https://sourceforge.net/projects/virtualgl/files/virtualgl_${VIRTUALGL_VERSION}_amd64.deb"; \
wget "https://sourceforge.net/projects/virtualgl/files/virtualgl32_${VIRTUALGL_VERSION}_amd64.deb"; \
apt-get install -y --no-install-recommends ./virtualgl_${VIRTUALGL_VERSION}_amd64.deb ./virtualgl32_${VIRTUALGL_VERSION}_amd64.deb; \
rm -f "virtualgl_${VIRTUALGL_VERSION}_amd64.deb" "virtualgl32_${VIRTUALGL_VERSION}_amd64.deb"; \
chmod u+s /usr/lib/libvglfaker.so; \
chmod u+s /usr/lib/libdlfaker.so; \
chmod u+s /usr/lib32/libvglfaker.so; \
chmod u+s /usr/lib32/libdlfaker.so; \
chmod u+s /usr/lib/i386-linux-gnu/libvglfaker.so; \
chmod u+s /usr/lib/i386-linux-gnu/libdlfaker.so; \
#
# clean up
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
rm -rf /var/lib/apt/lists/* /var/cache/apt/*;
#
# copy runtime configs
@ -261,9 +262,7 @@ COPY --from=gstreamer /usr/share/gstreamer /usr/share/gstreamer
#
# add healthcheck
HEALTHCHECK --interval=10s --timeout=5s --retries=8 \
CMD wget -O - http://localhost:${NEKO_SERVER_BIND#*:}/health || \
wget --no-check-certificate -O - https://localhost:${NEKO_SERVER_BIND#*:}/health || \
exit 1
CMD wget -O - http://localhost:${NEKO_SERVER_BIND#*:}/health || exit 1
#
# run neko

View file

@ -1,6 +1,6 @@
ARG UBUNTU_RELEASE=22.04
ARG CUDA_VERSION=12.2.0
ARG VIRTUALGL_VERSION=3.1.3-20250409
ARG VIRTUALGL_VERSION=3.1
ARG GSTREAMER_VERSION=1.22
#
@ -61,13 +61,13 @@ ARG UBUNTU_RELEASE
ARG VIRTUALGL_VERSION
# Make all NVIDIA GPUs visible by default
ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_VISIBLE_DEVICES all
# All NVIDIA driver capabilities should preferably be used, check `NVIDIA_DRIVER_CAPABILITIES` inside the container if things do not work
ENV NVIDIA_DRIVER_CAPABILITIES=all
ENV NVIDIA_DRIVER_CAPABILITIES all
#
# set vgl-display to headless 3d gpu card/// correct values are egl[n] or /dev/dri/card0:if this is passed into container
ENV VGL_DISPLAY=egl
ENV VGL_DISPLAY egl
#
# set custom user
@ -199,22 +199,23 @@ RUN VULKAN_API_VERSION=$(dpkg -s libvulkan1 | grep -oP 'Version: [0-9|\.]+' | gr
}" > /etc/vulkan/icd.d/nvidia_icd.json
#
# install an up-to-date version of VirtualGL
RUN apt-get update; \
apt-get install -y --no-install-recommends wget gpg ca-certificates; \
# Add VirtualGL GPG key
wget -q -O- https://packagecloud.io/dcommander/virtualgl/gpgkey | \
gpg --dearmor >/etc/apt/trusted.gpg.d/VirtualGL.gpg; \
# Download the official VirtualGL.list file
wget -q -O /etc/apt/sources.list.d/VirtualGL.list \
https://raw.githubusercontent.com/VirtualGL/repo/main/VirtualGL.list; \
# Install packages
# install VirtualGL and make libraries available for preload
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends virtualgl=${VIRTUALGL_VERSION}; \
wget "https://sourceforge.net/projects/virtualgl/files/virtualgl_${VIRTUALGL_VERSION}_amd64.deb"; \
wget "https://sourceforge.net/projects/virtualgl/files/virtualgl32_${VIRTUALGL_VERSION}_amd64.deb"; \
apt-get install -y --no-install-recommends ./virtualgl_${VIRTUALGL_VERSION}_amd64.deb ./virtualgl32_${VIRTUALGL_VERSION}_amd64.deb; \
rm -f "virtualgl_${VIRTUALGL_VERSION}_amd64.deb" "virtualgl32_${VIRTUALGL_VERSION}_amd64.deb"; \
chmod u+s /usr/lib/libvglfaker.so; \
chmod u+s /usr/lib/libdlfaker.so; \
chmod u+s /usr/lib32/libvglfaker.so; \
chmod u+s /usr/lib32/libdlfaker.so; \
chmod u+s /usr/lib/i386-linux-gnu/libvglfaker.so; \
chmod u+s /usr/lib/i386-linux-gnu/libdlfaker.so; \
#
# clean up
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
rm -rf /var/lib/apt/lists/* /var/cache/apt/*;
#
# copy runtime configs
@ -253,9 +254,7 @@ COPY --from=gstreamer /usr/share/gstreamer /usr/share/gstreamer
#
# add healthcheck
HEALTHCHECK --interval=10s --timeout=5s --retries=8 \
CMD wget -O - http://localhost:${NEKO_SERVER_BIND#*:}/health || \
wget --no-check-certificate -O - https://localhost:${NEKO_SERVER_BIND#*:}/health || \
exit 1
CMD wget -O - http://localhost:${NEKO_SERVER_BIND#*:}/health || exit 1
#
# run neko

View file

@ -33,7 +33,7 @@ redirect_stderr=true
[program:neko]
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
command=/usr/bin/neko serve --server.static "/var/www"
command=/usr/bin/neko serve --static "/var/www"
stopsignal=INT
stopwaitsecs=3
autorestart=true

Some files were not shown because too many files have changed in this diff Show more