{"id":29906064,"url":"https://github.com/function61/screen-server","last_synced_at":"2026-03-02T05:31:39.784Z","repository":{"id":42487996,"uuid":"271008840","full_name":"function61/screen-server","owner":"function61","description":"Minimal VNC-servable desktop environment with Firefox in a Docker container","archived":false,"fork":false,"pushed_at":"2025-02-26T09:21:34.000Z","size":324,"stargazers_count":11,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-01T20:32:58.742Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://function61.com/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/function61.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-09T13:22:53.000Z","updated_at":"2025-06-10T09:00:25.000Z","dependencies_parsed_at":"2025-01-20T10:31:18.862Z","dependency_job_id":"8404509e-5c34-472f-9861-73e5a93e8cd1","html_url":"https://github.com/function61/screen-server","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/function61/screen-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/function61%2Fscreen-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/function61%2Fscreen-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/function61%2Fscreen-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/function61%2Fscreen-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/function61","download_url":"https://codeload.github.com/function61/screen-server/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/function61%2Fscreen-server/sbom","scorecard":{"id":413799,"data":{"date":"2025-08-11","repo":{"name":"github.com/function61/screen-server","commit":"3239372324a9195726336fa469ca5fb509af6a1d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/27 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:9: update your workflow using https://app.stepsecurity.io/secureworkflow/function61/screen-server/build.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/function61/screen-server/build.yml/main?enable=pin","Warn: containerImage not pinned by hash: Dockerfile:1: pin your Docker image by updating ubuntu:latest to ubuntu:latest@sha256:7c06e91f61fa88c08cc74f7e1b7c69ae24910d745357e0dfe1d2c0322aaf20f9","Info:   0 out of   1 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   1 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: github.com/function61/.github/SECURITY.md:1","Info: Found linked content: github.com/function61/.github/SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: github.com/function61/.github/SECURITY.md:1","Info: Found text in security policy: github.com/function61/.github/SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2022-0493 / GHSA-p782-xgp4-8hr8"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T23:19:11.624Z","repository_id":42487996,"created_at":"2025-08-18T23:19:11.625Z","updated_at":"2025-08-18T23:19:11.625Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29993376,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T01:47:34.672Z","status":"online","status_checked_at":"2026-03-02T02:00:07.342Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-01T20:10:10.007Z","updated_at":"2026-03-02T05:31:39.654Z","avatar_url":"https://github.com/function61.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"⬆️ For table of contents, click the above icon\n\n![Build status](https://github.com/function61/screen-server/workflows/Build/badge.svg)\n[![Download](https://img.shields.io/docker/pulls/fn61/screen-server.svg?style=for-the-badge)](https://hub.docker.com/r/fn61/screen-server/)\n\nMinimal VNC-servable desktop environment with Firefox in a Docker container, for displaying web\ncontent on untrusted devices (like an old Android tablet).\n\nNice added benefit is that you can connect to the same screen simultaneously from other\ndevices like PCs as well, and if scripting is needed (show content X on screen Y), it's\neasier to achieve things like this on a PC than on a tablet.\n\n![](docs/network-drawing.png)\n\n\nWhy?\n----\n\nI had old Android tablets lying around. They are untrusted, because they are dangerous,\nbecause they haven't received software updates. I wanted to use one of them as always-on\ninfo screen.\n\nBecause they're untrusted, I:\n\n- taped off the camera \u0026 mic\n- put it in a guest Wifi network (with no access to my LAN)\n- configured firewall to not let the tablet in the internet, but only access to VNC port\n  in my LAN\n\n\nWhich VNC app for Android\n-------------------------\n\nThere's plenty to choose from, but they're not all equal. I've had success with bVNC.\n\n(Pro-tip: one of my tablets was so old (Android 4.2) that it didn't even support\n[RealVNC's current Android package](https://play.google.com/store/apps/details?id=com.realvnc.viewer.android).\nI downloaded an old version via apkpure.com, and firewalled the tablet off before beginning\nthe installation.)\n\n\nWhat's special about this image\n-------------------------------\n\n- Supports multiple screens (ran as separate users) with different resolutions\n- OSD notifications, OSD API for sending messages to screens over the network\n- Web UI w/ screen previews\n- Image size is small (for an image with a desktop environment and a web browser)\n\n\nHow to run\n----------\n\n```console\n$ docker run -d \\\n\t--name screen-server \\\n\t-p 5900:5900 \\\n\t-p 80:80 \\\n\t--shm-size 512m \\\n\t-e \"SCREEN_1=5900,800,1280,Galaxy Tab 2\" \\\n\tfn61/screen-server:TAG\n```\n\n\u003e [!NOTE]  \n\u003e if you get openbox error or error launching Firefox check the troubleshooting section in this README.\n\nPort 80 is for the web interface, port 5900 is for the example screen's VNC.\n\nThe format for the `SCREEN_n` parameter is `\u003cVNC port\u003e,\u003cdisplay width\u003e,\u003cheight\u003e,\u003cscreen name\u003e,[\u003cinput device\u003e]`\n\nWhy screen name? It's good if you have many screens. Web UI \u0026 some VNC clients show it.\n\nYou can optionally add **physical input devices** like a keyboard-mouse to a screen. There's a\nseparate README section for it.\n\nIf you have more than one screen, just add `SCREEN_2` and so on..\n\nNOTE: `--shm-size` is important - with too small value Firefox \u0026 Chromium crash with more\nwebsites (or \u003e= 1 tab).\n\n\nNote about state\n----------------\n\nUsers should assume all state gets wiped daily. It doesn't, but we have absolutely no plans\nto support migrating state (like Firefox configuration or installed plugins) when new\nversions of this image gets released. When you spin up a new container with the new version,\nall state gets lost.\n\n\nWeb UI\n------\n\nIt shows you the preview of what's on all the screens.\n\n![](docs/web-ui.png)\n\nYou can click on the preview to launch [web-based VNC](https://github.com/novnc/noVNC) session.\n\nFirefox users should read [this pro-tip](https://stackoverflow.com/a/12042843).\n\n\nMap keyboard/mouse inside the container\n---------------------------------------\n\nTODO: improve these instructions\n\nSee [accompanying blog post](https://joonas.fi/2020/12/attach-a-keyboard-to-a-docker-container/)\n\nYou need to add the `evdev` device file to Docker run `--device` argument. The blog post explains more.\n\n### Troubleshooting\n\nIf you run into problems, `$ cat` the input device from inside the container to test it works.\nThe blog post also explains this.\n\n\n\nSending OSD notifications\n-------------------------\n\nMy use case was to display messages sent by my home automation in the screen that is always\nvisible.\n\n```console\n$ curl -d \"msg=Hello world\" http://localhost/api/screen/1/osd/notify\n```\n\nThe notification is visible for a few seconds.\n\nWe have plugin drivers for different OSD notification implementations -  currently we use\n[zenity](https://en.wikipedia.org/wiki/Zenity), which is not pretty. A prettier way could\nbe to show the notification as a full-screen webpage (so we get CSS animations etc.), but\nthat's still TODO.\n\n![](docs/osd-notification.png)\n\n\nRoadmap\n-------\n\n- Use standard `$ notify-send` and its DBUS protocol for OSD-notifications. Pick a nice front-end.\n- Instead of supporting multiple screens (and users) inside container, just spin up a container per\n  screen? Better for failure isolation, and you don't have to take all screens down if you want to\n  reconfigure (think: map keyboard) one. Virtual memory etc. should make this not use more memory..\n- Integrate screen-server-client (audio playing extensions, screen on/off API) into this repo\n- Go back to Alpine Linux. It shaved off a large amount of disk space, but Widevine (= DRM) didn't\n  work in Alpine's Firefox (due to glibc incompatibility I think), and thus I couldn't get Spotify\n  web player to work.\n\nTroubleshooting\n---------------\n\n### openbox error or error launching Firefox\n\nyou may need to add [`--security-opt` arg](https://github.com/function61/screen-server/issues/8#issuecomment-2058301288)\n\n\nCredits\n-------\n\nI learned how to plug Xvfb, x11vnc, Openbox together from\n[danielguerra69/alpine-vnc](https://github.com/danielguerra69/alpine-vnc). I added Firefox,\nprocess management in Go (instead of Python), multi-screen support, OSD etc.\n\n\nLinks\n-----\n\n- Similar but for Wayland: [bbusse/swayvnc-firefox](https://github.com/bbusse/swayvnc-firefox)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffunction61%2Fscreen-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffunction61%2Fscreen-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffunction61%2Fscreen-server/lists"}