{"id":15007178,"url":"https://github.com/amateur80lvl/lxcex","last_synced_at":"2025-10-30T11:31:33.111Z","repository":{"id":214611580,"uuid":"735402455","full_name":"amateur80lvl/lxcex","owner":"amateur80lvl","description":"Lightweight privacy-focused desktop operating system based on Devuan and LXC","archived":false,"fork":false,"pushed_at":"2024-10-18T04:46:02.000Z","size":1728,"stargazers_count":9,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-19T11:24:06.521Z","etag":null,"topics":["containers","devuan","linux","linux-desktop","linux-distribution","linux-distro","lxc"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/amateur80lvl.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":"2023-12-24T19:44:14.000Z","updated_at":"2024-10-18T04:46:06.000Z","dependencies_parsed_at":"2024-01-18T00:57:04.517Z","dependency_job_id":"77d24f20-4936-4af0-908e-6071cbde5963","html_url":"https://github.com/amateur80lvl/lxcex","commit_stats":{"total_commits":171,"total_committers":3,"mean_commits":57.0,"dds":"0.052631578947368474","last_synced_commit":"f5ef3044adb7bf21fbe45453a079c3f0ed160763"},"previous_names":["amateur80lvl/lxcex"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amateur80lvl%2Flxcex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amateur80lvl%2Flxcex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amateur80lvl%2Flxcex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amateur80lvl%2Flxcex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amateur80lvl","download_url":"https://codeload.github.com/amateur80lvl/lxcex/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238960344,"owners_count":19559246,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["containers","devuan","linux","linux-desktop","linux-distribution","linux-distro","lxc"],"created_at":"2024-09-24T19:05:11.716Z","updated_at":"2025-10-30T11:31:27.567Z","avatar_url":"https://github.com/amateur80lvl.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LXCex\n\nLightweight privacy-focused desktop operating system based on Devuan and LXC.\nA project for self-education, and yet another attempt to make an alternative\nto [Qubes OS](https://www.qubes-os.org/).\nThis is not a distro yet and probably never will.\nThis is a set of files and patches, a simple `makecex` script,\nand an instruction à la [LFS](https://www.linuxfromscratch.org/).\n\nWork in progress.\n\n\n## Overview\n\n* The base system (host system, or Dom0 in terms of Qubes) is running Sway.\n* Networking container manages all physical devices, runs firewall and apt-cacher-ng.\n* Virtual internal network provides truly static IP addresses to containers,\n  making more or less complex routing robust when external IP address and/or devices change.\n* Additional networking containers may run different VPNs for work, entertainment, banking, etc.\n* User containers run Weston, Cage, Xwayland, etc. instances which get nested in Sway.\n\nAt the moment, this system reflects my experience and is full of personal preferences.\nSome of them are quite baseless.\nI swear I'll get rid of them as soon as the number of users will go beyond 1.5.\nBut in general, the rationale is as follows:\n\n## Rationale\n\n* keep attack surface and fingerprinting surface as small as possible\n* make [plausible deniability](https://github.com/amateur80lvl/pdt) easy\n\n## Installation\n\n### makecex\n\nA bootable media with live system can be generated with\n[makecex](https://github.com/amateur80lvl/lxcex/tree/main/makecex).\nYou'll need a PPA which can be created with\n[prepare](https://github.com/amateur80lvl/lxcex/tree/main/packages/prepare) and\n[build](https://github.com/amateur80lvl/lxcex/tree/main/packages/build) scripts.\n\nOnly legacy boot mode is supported for amd64 for now.\n\nThe script contains parameters at the beginning, revise them carefully before running.\nYou can write modified parameters to `makecex.conf` instead of making changes to the script.\n\n\n### by hands\n\n* [Chapter 1. Installing the base system with debootstrap](https://github.com/amateur80lvl/lxcex/tree/main/book/ch1-installing-base-system.md)\n* [Chapter 2. The basic networking](https://github.com/amateur80lvl/lxcex/tree/main/book/ch2-basic-networking.md)\n* [Chapter 3. LXC and the base container](https://github.com/amateur80lvl/lxcex/tree/main/book/ch3-lxc-and-base-container.md)\n* [Chapter 4. Networking](https://github.com/amateur80lvl/lxcex/tree/main/book/ch4-networking.md)\n* [Chapter 5. Desktop Environment](https://github.com/amateur80lvl/lxcex/tree/main/book/ch5-desktop-environment.md)\n* [Chapter 6. Pipewire](https://github.com/amateur80lvl/lxcex/tree/main/book/ch6-pipewire.md)\n* [Chapter 7. Plausible Deniability](https://github.com/amateur80lvl/lxcex/tree/main/book/ch7-plausible-deniability.md)\n* [Chapter 8. Sharing files](https://github.com/amateur80lvl/lxcex/tree/main/book/ch8-sharing-files.md)\n\n\n## Experience\n\nDrafts/Sandbox section.\n\n## idmapped mounts vs uidmapshift\n\n**Since LXCex moved to idmapped mounts, file permissions became more important.**\n**With `uidmapshift` all container data was inaccessible from unprivileged user on the base system.**\n**That's no longer the case with idmapped mounts because unprivileged users**\n**across base system and containers have common ids.**\n\nMake sure all subdirectories in `/var/lib/lxc` have minimal permissions and are not readable by `other` at least.\nThe same applies to the container data stored elsewhere.\n\nHowever, for idmapped mounts to work, the minimal permissions must include directory traversal for others.\nThis could be worked around using `setfacl`, but that comlication overweights the convenience.\n\nIf all the above is a security concern, do not use idmapped mounts.\n\n## Quirks\n\n* Something smashes `/dev/ptmx` after a while.\n* Under Weston, drop-down menus in Kate appear with a significant delay.\n  Sympthoms look like those described in merge request 1123\n* Weston terminal does not honour user's shell from /etc/passwd and uses `sh`\n  if Weston is started by runit, where parent shell is `sh`.\n* When maximizing Chromium, top left position sometimes remains unchanged.\n* Copy-pasting from Kate to Weston terminal drops newlines.\n  This might be a security precaution, but I'd like a dialog then. Same as in linuxmint.\n\n## TODO\n\n* get rid of hardcoded `lxcex`, let the user to customize that?\n* find the best way to create /run/user/\u003cuid\u003e in containers\n* automatic move network adapters to container (udev rule?)\n* DHCP\n* improve UX\n* copy-paste across containers\n* pipewire (video)\n* LibreOffice complains /proc is not mounted. What, excuse me, fucking for?\n  Even such a malware as modern web browsers does not need it.\n  Given that it's mounted, indeed. With restrictions.\n\n## Wishes (TODO list?)\n\n* A decent panel for Sway.\n* Disable window decoration in Weston's wayland backend, not only in headless.\n* A decent replacement for runit.\n* Weston and wlroots-based compositors close session when connection to the socket\n  is lost. Need re-connect feature.\n\n\n## Changeblog\n\n### Nov 2, 2024\n\n* Revised sharing at last. See updated Chapter 8.\n* Moved to idmapped rootfs. Keeping `uidmapshift` around for now.\n  As a replacement for `ls -l /var/lib/lxc` that showed ids of `uidmapshift`ed, containers,\n  there's an `lxcex-idmap` script now that shows subordinate user ids for each container\n  that use idmap.\n\n### Oct 22, 2024\n\nOkay, dropping a line here. I still seem to be a single user of all this shit and,\nas my African friends say, \"daz good!\"\n\nLots of features wanted. Number one is to get rid of runit. Number two is UI utils.\nAll others wishes are just a little things.\n\n### Mar 3, 2024\n\nSo far so good. New Chapter 8 is out.\n\n### Feb 14, 2024\n\nThree months since inception, and now I can say farewell, linuxmint.\nLXCex is on all my laptops from now onwards.\n\nMajor updates:\n* Bugfixes, of course.\n* start-user-containers now detects running system compositor, so it's much easier to run GUI containers manually.\n* dist-upgrade script\n* chapter 7\n\n### Jan 31, 2024\n\nYet another milestone: [makecex](https://github.com/amateur80lvl/lxcex/tree/main/makecex) is out!\nThis script generates bootable media.\nNot excessively tested, it just works just for me.\n\n### Jan 27, 2024\n\nPackages repo is out. For now the only package there is uidmapshift.\nPlanning to add patched version of libpulse, thus getting rid of file permission fixer.\n\nAlthough death from laugh is not my ultimate goal, I had to add signing key for me, anonymous.\n\nAutomation is on the way. Commenced after I managed to crash the system simply by remounting /var/lib/lxc with running containers.\nDid not realize it's so dangerous.\nThis action destroyed all mounted partitions including backup USB stick which had nothing to do with that. Why???\n\n### Jan 17, 2024\n\nIt plays music! Initial version of Chapter 6 is out, to be updated.\n\n### Jan 16, 2024\n\nXFCE desktop environment is working!\n\n### Dec 30, 2023\n\nTag: 0.0.2\n* Misc. tweaks.\n* Made --no-install-recommends the default option, chapters 1-4 need testing.\n\n### Dec 29, 2023\n\nInitial commit and release.\n\n## Tips and tricks\n\n### Upgrading the system\n\nYou may wonder how to issue `apt upgrade` for a dozen of containers including the base system.\nThat's what\n[dist-upgrade](https://github.com/amateur80lvl/lxcex/tree/main/base-system/root/dist-upgrade)\nscript is for.\nIt is based on\n[lxcex-chroot](https://github.com/amateur80lvl/lxcex/tree/main/base-system/usr/local/bin/lxcex-chroot)\nwhich runs arbitraty command, properly chrooting to the container's rootfs.\n\n### Firefox\n\nThey lauched apt repository, so it's worth to follow\n[their instructions](https://support.mozilla.org/en-US/kb/install-firefox-linux)\n\nAt the time of writing, firefox (version 123) uses wayland by default.\nIf you remember, WAYLAND_DISPLAY is reset in\n[/home/user/.config/sv/xfce4/run](https://github.com/amateur80lvl/lxcex/tree/main/containers/xfce4/rootfs/home/user/.config/sv/xfce4/run)\nand this makes firefox to enter infinite loop saying\n\n`Warning: ConnectToCompositor() try again : Connection refused`\n\nThere are two options:\n* add --display=:0.0 command line option\n* set WAYLAND_DISPLAY when running firefox\n\nI tried both. Initially I chose the latter, using a script:\n```\n#!/bin/sh\n\nif [ -n \"$X_WAYLAND_DISPLAY\" ] ; then\n    export WAYLAND_DISPLAY=$X_WAYLAND_DISPLAY\nelse\n    # fallback\n    export WAYLAND_DISPLAY=wayland-1\nfi\n\nfirefox\n```\n\nHowever, this makes copy-paste troublesome so I returned to X mode for now.\n\n### NFS + autofs\n\nMy initial setups were weird and fragile simply because of lack of understanding of shared subtrees.\n* https://www.kernel.org/doc/html/latest/filesystems/sharedsubtree.html\n* https://lwn.net/Articles/689856/\n\nHere's the solution:\n1. Make some mount point recursively shared. You can't make an arbitrary directory in the file system\n   rshared (that was my point of misunderstanding), it should be an actual mount point,\n   i.e. a directory where some filesystem is mounted.\n\n   I want to use `/mnt/autofs` for autofs so let's mount a tmpfs there and rshare it:\n   ```\n   mkdir -p /mnt/autofs\n   mount -t tmpfs -o size=64K --make-rshared tmpfs /mnt/autofs\n   mkdir /mnt/autofs/myserver\n   ```\n2. Create autofs configuration:\n   ```\n   mkdir /etc/auto.maps\n   echo \"/mnt/autofs/myserver /etc/auto.maps/myserver\" \u003e/etc/auto.master.d/myserver.autofs\n   echo \"shared-dir myserver.example.com:/var/share/top-secret\" \u003e/etc/auto.maps/myserver\n   ```\n   and restart autofs.\n\n3. Add the following line to the container's config:\n   ```\n   lxc.mount.entry = /mnt/autofs mnt/autofs none create=dir,rbind 0 0\n   ```\n\nStart the container. Inside, `ls /mnt/myserver/shared-dir` should work as expected.\n\nHowever, user:group will be nobody:nogroup and I have no idea how to setup correct id mapping.\n\n\n### Editing main menu\n\n`menulibre` looks kinda bloatware and currently is totally broken in excalibur.\nHowever, its quite easy to edit menus manually:\n* All menu entries are listed in `.config/menus/xfce-applications.menu`\n* Configuration files for each entry are in `.local/share/applications`\n\n### Running programs as a different users\n\nContainers are great to isolate workspaces as if they were running on separate machines.\nThis greatly simplifies such things as networking which are too error-prone\nor impossible to maintain within a single system.\n\nBut at container level everything is still the same: single home directory where all\napplications have full access to user's data.\n\nThis is dangerous.\nPotentially, every program that use network may leak your sensitive data, even unintentially.\n\nBasically, all programs that work with your data should be run in a container with\ndisabled networking, and probably I'll end up with such arrangement.\n\nBut for now I have a few legacy XFCE environments each running in its own container.\nA temporary solution I deployed within those containers is restricted network access\nfor the main user and running all networking software as a different users.\nThis software includes Firefox, Chromium, Mullvad, and Tor browsers, plus Thunderbird.\nOf course, some do support Wayland already but LXCex still has copy-pasting issues\nand it's a blocking factor to run them natively.\n\nHere's the setup, on the example of Firefox,\nwhich can be used as a boilerplate for other programs.\n\nFirst, create a separate user:\n```\nuseradd -g users --skel /etc/skel --shell /bin/bash --create-home firefox\n```\nThen, move directories:\n```\nmkdir /home/firefox/.cache\nmv /home/user/.mozilla /home/firefox/\nmv /home/user/.cache/firefox /home/firefox/.cache/\nchown -R firefox /home/firefox\n```\nNext, prepare a script `/usr/local/bin/start-firefox`:\n```\n#!/bin/sh\n\nUSER=firefox\n\nif [ -z \"$1\" ] ; then\n    xhost +SI:localuser:$USER\n    exec sudo $0 dosu\nelif [ \"$1\" = \"dosu\" ] ; then\n    exec su -l -c \"$0 run\" $USER\nelif [ \"$1\" = \"run\" ] ; then\n    cd /home/$USER\n    . /usr/local/share/lxcex-xdg.sh\n    export DISPAY=:0.0\n    exec firefox --display=:0.0\nfi\n```\nActually, `DISPLAY` environment variable is not necessary here, but this script\ncan be used as a boilerplate to run other apps so I intentionally left it.\n\nFinally, create `/etc/sudoers.d/50-start-firefox` (alas, sudo is required):\n```\nuser ALL = NOPASSWD: /usr/local/bin/start-firefox dosu\n```\nYou may need to modify XFCE start menu entry.\nAnd to add -P option for the first time, otherwise firefox may start with a blank profile.\n\nIt's a good idea to share `Downloads` directory.\nPrevious approach was a group-writeable directory with symlinks to it, but the best way is `lxces-share`.\n\nLet `Downloads` direcroty be in `user`'s home directory, as it used to.\nThen, create the following `sharetab` for the container:\n```\n/var/lib/lxc/\u003ccontainer-name\u003e/rootfs/home/user/Downloads  firefox  /home/firefox/Downloads\n```\nAnd use hooks in container configuration, as shown in Chapter 8:\n```\nlxc.hook.pre-start = /usr/local/bin/lxcex-share\nlxc.hook.mount     = /usr/local/bin/lxcex-share\nlxc.hook.start     = /usr/local/bin/lxcex-share\nlxc.hook.post-stop = /usr/local/bin/lxcex-share\n```\n\n## Miscellaneous notes\n\n### links\n\n* [Awesome Wayland: A curated list of Wayland code and resources.](https://github.com/natpen/awesome-wayland)\n* [Sway wiki](https://github.com/swaywm/sway/wiki)\n* [PipeWire Guide](https://github.com/mikeroyal/PipeWire-Guide)\n* About [Xwayland](https://ofourdan.blogspot.com/2023/10/xwayland-rootful-part1.html). However, -geometry does not work for me.\n* [Lumina](https://lumina-desktop.org/): sans-bloatware desktop environment\n* [Hyperbola](https://www.hyperbola.info/): yet another amazing project with\n  [strong philosophy](https://wiki.hyperbola.info/doku.php?id=en:philosophy:incompatible_packages\u0026redirect=1)\n\n### socket proxies\n\nDiscovered this article when wrote chapter 6:\nhttps://discuss.linuxcontainers.org/t/audio-via-pulseaudio-inside-container/8768\nThey use LXD and it's worth to take a look at the implementation od socket proxies.\nCan we use them to retain container socket and reconnect to the host socket when\nthe base compositor gets restarted? Or when a container resumes from hibernation?\n\n### mount namespaces and shared subtrees\n\nAgain,\n* https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt\n* https://lwn.net/Articles/689856/\n\nI didn't get why I had to\n```bash\nmount --make-shared /run\n```\ni.e. `/run`, not `/run/user` if I did `mount --rbind /run/user \"${LXC_ROOTFS_MOUNT}/run/host/run/user\"`\nin containers and wanted all uid submounts to propagate.\n\nAfter re-reading that a few times it should be clear, eventually.\n\n### smartd tweaks\n\n`smartd` is the most reliable tool to disable HDD spindowns thus far:\n1. edit `/etc/default/smartmontools`:\n   ```\n   smartd_opts=\"--interval=10 --attributelog=- --savestate=-\"\n   ```\n   Key option is `--interval`, others disable saving state which I never needed.\n2. Make sure `-n` option is `never` in `etc/smartd.conf`, i.e.:\n   ```\n   DEVICESCAN -d removable -n never -m root -M exec /usr/share/smartmontools/smartd-runner\n   ```\n\n### More packages\n\nMy extra packages, just for the record.\n\n* Fonts: `gnome-font-viewer`, looks unnecessary\n* Images: `gthumb`\n* Kate: when installed in XFCE, it needs some theme. I used `breeze-icon-theme`.\n* KDE `systemsettings`: installed just in case, zero profit so far.\n* Ungoogled chromium needs: `libnss3`, `libasound2`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famateur80lvl%2Flxcex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famateur80lvl%2Flxcex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famateur80lvl%2Flxcex/lists"}