diff --git a/.github/scripts/build-docs.py b/.github/scripts/build-docs.py index e2b1ec5..34ae247 100644 --- a/.github/scripts/build-docs.py +++ b/.github/scripts/build-docs.py @@ -138,72 +138,98 @@ def md_to_html(md): html.append(convert_table(rows)) continue - # Ordered lists - olm = re.match(r'^\s*\d+\.\s+(.+)$', line) - if olm: - items = [] - while i < len(lines) and re.match(r'^\s*\d+\.\s+', lines[i]): - item_text = re.sub(r'^\s*\d+\.\s+', '', lines[i]) - item_html = inline_format(item_text) - i += 1 - extra = [] - while i < len(lines): - s = lines[i].lstrip() - indent = len(lines[i]) - len(s) - if indent >= 3 and s.startswith('```'): - ch, i = consume_code(lines, i) - extra.append(ch) - elif indent >= 3 and s.startswith('> '): - extra.append(f'
{inline_format(s[2:])}
') - i += 1 - elif lines[i].strip() == '': - i += 1 - continue - elif indent >= 3 and s.strip(): - extra.append(inline_format(s)) - i += 1 - else: - break - items.append(f'
  • {" ".join(extra) if item_html == "" else item_html}{"".join(extra) if item_html != "" else ""}
  • ') - # Fix: combine item_html with extra - fixed_items = [] - for item in items: - fixed_items.append(item) - html.append('
      \n' + '\n'.join(items) + '\n
    ') - continue + # Lists (ordered and unordered) — stack-based recursive nesting + def is_list_item(ln): + return bool(re.match(r'^(\s*)(?:\d+\.|[-*+])\s+', ln)) + + def item_indent(ln): + m = re.match(r'^(\s*)', ln) + return len(m.group(1)) if m else 0 + + def item_tag(ln): + """Return 'ol' for ordered, 'ul' for unordered.""" + stripped = ln.lstrip() + return 'ol' if re.match(r'^\d+\.\s+', stripped) else 'ul' - # Unordered lists - ulm = re.match(r'^[\s]*[-*+]\s+', line) - if ulm: - items = [] - while i < len(lines) and re.match(r'^[\s]*[-*+]\s+', lines[i]): - item_text = re.sub(r'^[\s]*[-*+]\s+', '', lines[i]) - item_html = inline_format(item_text) + def item_text_content(ln): + return re.sub(r'^\s*(?:\d+\.|[-*+])\s+', '', ln) + + def consume_list(lines, start, base_indent): + """Recursively parse a list starting at `start` with `base_indent`. + Returns (html_string, next_line_index).""" + i = start + tag = item_tag(lines[i]) + parts = [f'<{tag}>'] + while i < len(lines): + ln = lines[i] + if not ln.strip(): + # blank line — peek ahead to see if list continues + j = i + 1 + while j < len(lines) and not lines[j].strip(): + j += 1 + if j < len(lines) and is_list_item(lines[j]) and item_indent(lines[j]) >= base_indent: + i = j + continue + break + if not is_list_item(ln): + break + ind = item_indent(ln) + if ind < base_indent: + break + if ind > base_indent: + # deeper — recurse as nested list inside current
  • + nested_html, i = consume_list(lines, i, ind) + parts.append(nested_html) + continue + # Same indent — new sibling list item + # Close previous
  • if open + if parts[-1] != f'<{tag}>': + parts.append('
  • ') + text = inline_format(item_text_content(ln)) + parts.append(f'
  • {text}') i += 1 - extra = [] + # Consume continuation content (code blocks, blockquotes, plain text) while i < len(lines): - s = lines[i].lstrip() - indent = len(lines[i]) - len(s) - if indent >= 3 and s.startswith('```'): + cont = lines[i] + if not cont.strip(): + # blank — check if continuation follows + j = i + 1 + while j < len(lines) and not lines[j].strip(): + j += 1 + if j < len(lines): + cind = item_indent(lines[j]) if is_list_item(lines[j]) else (len(lines[j]) - len(lines[j].lstrip())) + if cind > base_indent: + i = j + continue + break + s = cont.lstrip() + cind = len(cont) - len(s) + if is_list_item(cont) and item_indent(cont) > base_indent: + nested_html, i = consume_list(lines, i, item_indent(cont)) + parts.append(nested_html) + elif is_list_item(cont) and item_indent(cont) == base_indent: + break + elif cind > base_indent and s.startswith('```'): ch, i = consume_code(lines, i) - extra.append(ch) - elif indent >= 3 and s.startswith('> '): - extra.append(f'
    {inline_format(s[2:])}
    ') + parts.append(ch) + elif cind > base_indent and s.startswith('> '): + parts.append(f'
    {inline_format(s[2:])}
    ') i += 1 - elif lines[i].strip() == '': - i += 1 - continue - elif indent >= 3 and s.strip(): - extra.append(inline_format(s)) + elif cind > base_indent and s.strip(): + parts.append(f'

    {inline_format(s)}

    ') i += 1 else: break - items.append(f'
  • {" ".join(extra) if item_html == "" else item_html}{"".join(extra) if item_html != "" else ""}
  • ') - # Fix the combine - combined = [] - for item in items: - combined.append(item) - html.append('') + # Close any open
  • + if parts and parts[-1] != f'<{tag}>': + parts.append('
  • ') + parts.append(f'') + return '\n'.join(parts), i + + if is_list_item(line): + base = item_indent(line) + list_html, i = consume_list(lines, i, base) + html.append(list_html) continue # Paragraph @@ -251,7 +277,7 @@ def convert_table(rows): SECTION_ORDER = {'Basics': 0, 'Guides': 1, 'Recipes': 2, 'Reference': 3} FALLBACK_TITLES = { - 'getting-started': 'Getting Started', 'installation-android': 'Android Installation', + 'installation-android': 'Android Installation', 'installation-linux': 'Linux Installation', 'features': 'Features Deep Dive', 'gpu-acceleration': 'GPU Acceleration', 'kernel-configuration': 'Kernel Configuration', 'usage-android-app': 'Android App Usage', 'linux-cli': 'Linux CLI Usage', @@ -261,7 +287,7 @@ def convert_table(rows): } FALLBACK_SECTIONS = { - 'getting-started': 'Basics', 'installation-android': 'Basics', 'installation-linux': 'Basics', + 'installation-android': 'Basics', 'installation-linux': 'Basics', 'features': 'Guides', 'gpu-acceleration': 'Guides', 'kernel-configuration': 'Guides', 'usage-android-app': 'Guides', 'linux-cli': 'Guides', 'cool-things-you-can-do': 'Recipes', @@ -270,7 +296,7 @@ def convert_table(rows): } FALLBACK_ORDER = { - 'getting-started': 1, 'installation-android': 2, 'installation-linux': 3, + 'installation-android': 1, 'installation-linux': 2, 'features': 1, 'gpu-acceleration': 2, 'kernel-configuration': 3, 'usage-android-app': 4, 'linux-cli': 5, 'cool-things-you-can-do': 1, @@ -279,7 +305,6 @@ def convert_table(rows): } FALLBACK_DESC = { - 'getting-started': 'Get started with Droidspaces \u2014 a lightweight ~400KB Linux container runtime for Android and Linux. Install, configure, and run your first container in minutes.', 'installation-android': 'Step-by-step Android installation guide for Droidspaces. Root your device, install the APK, set up the backend, and run Linux containers with zero terminal commands.', 'installation-linux': 'Install Droidspaces on Linux desktop or server. Download the tarball, extract the binary, create a rootfs image, and boot your first container.', 'features': 'Deep dive into every Droidspaces feature: namespace isolation, init system support, OverlayFS volatile mode, GPU acceleration, cgroup isolation, seccomp shields, and Android-specific tuning.', @@ -296,7 +321,6 @@ def convert_table(rows): } FALLBACK_KEYWORDS = { - 'getting-started': 'Droidspaces getting started, Linux containers Android, container runtime, namespaces, rootfs, kernel requirements', 'installation-android': 'install Droidspaces Android, rooted Android container, APK install, atomic backend, sparse image', 'installation-linux': 'install Droidspaces Linux, Linux container runtime, rootfs tarball, ext4 image, Linux namespaces', 'features': 'Droidspaces features, namespace isolation, cgroup v2, OverlayFS, volatile mode, init system, GPU hardware access', @@ -468,7 +492,7 @@ def make_page(title, body, slug, nav_template, footer_template, pages, is_index= .sidebar-content {{ flex: 1; min-width: 0; padding: 2rem 2rem 4rem; - max-width: 960px; + max-width: none; }} .sidebar-content h1 {{ font-family: var(--mono); font-size: clamp(1.5rem, 2.5vw, 2rem); @@ -499,12 +523,14 @@ def make_page(title, body, slug, nav_template, footer_template, pages, is_index= .sidebar-content strong {{ color: var(--text); }} .sidebar-content a {{ color: var(--accent2); text-decoration: none; + word-break: break-word; overflow-wrap: anywhere; }} .sidebar-content a:hover {{ text-decoration: underline; }} .sidebar-content code {{ font-family: var(--mono); font-size: 0.82rem; background: var(--bg3); padding: 0.15rem 0.4rem; border-radius: 4px; color: var(--accent2); + word-break: break-word; overflow-wrap: anywhere; }} .sidebar-content pre {{ background: var(--bg2); border: 1px solid var(--border); @@ -554,13 +580,17 @@ def make_page(title, body, slug, nav_template, footer_template, pages, is_index= }} .table-wrap {{ overflow-x: auto; + -webkit-overflow-scrolling: touch; margin-bottom: 1.5rem; }} .table-wrap table {{ + width: max-content; + min-width: 100%; margin-bottom: 0; }} .sidebar-content table {{ - width: 100%; border-collapse: collapse; font-size: 0.85rem; + width: max-content; min-width: 100%; + border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1.5rem; }} .sidebar-content th {{ @@ -573,7 +603,8 @@ def make_page(title, body, slug, nav_template, footer_template, pages, is_index= .sidebar-content td {{ padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); - word-break: break-word; + white-space: normal; word-break: normal; + overflow-wrap: break-word; max-width: 300px; }} .sidebar-content img {{ max-width: 100%; border-radius: 8px; border: 1px solid var(--border); @@ -850,9 +881,7 @@ def fetch_kernel_patches(): parts.append('') return '\n'.join(parts) -def build_downloads_page(root, nav_template, footer_template): - dl_nav = nav_template.replace('{{FEATURES_HREF}}', '/#features').replace('{{DOCS_STYLE}}', '') - releases = [] +def fetch_latest_release(): try: url = 'https://api.github.com/repos/ravindu644/Droidspaces-OSS/releases?per_page=5' req = urllib.request.Request(url) @@ -861,8 +890,55 @@ def build_downloads_page(root, nav_template, footer_template): req.add_header('Authorization', f'Bearer {token}') with urllib.request.urlopen(req, timeout=10) as resp: releases = json.loads(resp.read()) - except: - pass + except Exception: + return None + + if not releases: + return None + + latest = releases[0] + version = latest.get('tag_name', 'v6.2.0') + date = latest.get('published_at', '2026-05-22')[:10] + apk_url = '' + tar_url = '' + for a in latest.get('assets', []): + name = a.get('name', '') + if name.endswith('.apk'): + apk_url = a.get('browser_download_url', '') + elif name.endswith('.tar.gz'): + tar_url = a.get('browser_download_url', '') + body = latest.get('body', '') + changelog = md_to_html(body) if body else '

    No changelog available.

    ' + + older_rows = [] + for r in releases[1:]: + tag = r.get('tag_name', '') + rd = r.get('published_at', '')[:10] + rn = r.get('name', tag) + older_rows.append( + f'{rn}{rd}' + f'Download' + ) + older_html = ( + '
    ' + + '\n'.join(older_rows) + + '
    VersionDate
    ' + if older_rows else '' + ) + + return { + 'version': version, + 'date': date, + 'apk_url': apk_url, + 'tar_url': tar_url, + 'changelog': changelog, + 'older_html': older_html, + } + + +def build_downloads_page(root, nav_template, footer_template): + dl_nav = nav_template.replace('{{FEATURES_HREF}}', '/#features').replace('{{DOCS_STYLE}}', '') + release_info = fetch_latest_release() patches_html = '''

    GKI

    below-kernel-6.12

    ''' - if releases: - latest = releases[0] - version = latest.get('tag_name', 'v6.2.0') - date = latest.get('published_at', '2026-05-22')[:10] - apk_url = tar_url = '' - for a in latest.get('assets', []): - n = a['name'] - if n.endswith('.apk'): - apk_url = a['browser_download_url'] - elif n.endswith('.tar.gz'): - tar_url = a['browser_download_url'] - body = latest.get('body', '') - changelog = md_to_html(body) if body else '

    No changelog available.

    ' - older_rows = [] - for r in releases[1:]: - tag = r['tag_name'] - rd = r.get('published_at', '')[:10] - rn = r['name'] - older_rows.append(f'{rn}{rd}Download') - older_html = '
    ' + '\n'.join(older_rows) + '
    VersionDate
    ' if older_rows else '' + if release_info: + version = release_info['version'] + date = release_info['date'] + apk_url = release_info['apk_url'] + tar_url = release_info['tar_url'] + changelog = release_info['changelog'] + older_html = release_info['older_html'] else: version = 'v6.2.0' date = '2026-05-22' @@ -1034,10 +1097,10 @@ def generate_sitemap(root): '404.html': ('/404.html', 0.1), } doc_priorities = { - 'getting-started': 0.9, 'installation-android': 0.8, 'installation-linux': 0.8, + 'installation-android': 0.9, 'installation-linux': 0.8, 'features': 0.7, 'gpu-acceleration': 0.7, 'kernel-configuration': 0.7, 'usage-android-app': 0.7, 'linux-cli': 0.7, 'cool-things-you-can-do': 0.6, - 'common-errors': 0.6, 'troubleshooting': 0.6, 'community-supported-devices': 0.5, + 'troubleshooting': 0.6, 'community-supported-devices': 0.5, 'nix-nixos': 0.5, 'uninstallation': 0.5, } urls = [(loc, pri) for fname, (loc, pri) in priorities.items()] @@ -1056,7 +1119,7 @@ def generate_sitemap(root): print("OK: sitemap.xml") if __name__ == '__main__': - root = '/home/tharukrj/Projects/droidspaces.github.io' + root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) docs_dir = os.path.join(root, 'docs/content') out_dir = os.path.join(root, 'docs') @@ -1095,6 +1158,19 @@ def generate_sitemap(root): index_html, flags=re.DOTALL ) + release_info = fetch_latest_release() + if release_info: + version = release_info['version'] + index_html = re.sub( + r'(
    )v[^<]+( · Open Source
    )', + lambda m: f'{m.group(1)}{version}{m.group(2)}', + index_html, + ) + index_html = re.sub( + r'("softwareVersion"\s*:\s*")v?[^"\n]+(",)', + lambda m: f'{m.group(1)}{version.lstrip("v")}{m.group(2)}', + index_html, + ) index_html = index_html.replace('{{FOOTER}}', footer_template) with open(index_path, 'w') as f: f.write(index_html) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 00076fe..9cf0104 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -3,24 +3,23 @@ name: Build Docs on: repository_dispatch: types: [docs-updated] + workflow_dispatch: jobs: build: runs-on: ubuntu-latest + permissions: + contents: write steps: - uses: actions/checkout@v4 - name: Fetch latest docs from source repo - env: - PAT: ${{ secrets.SOURCE_REPO_PAT }} run: | - REPO="https://github.com/YOUR_USERNAME/YOUR_SOURCE_REPO.git" - if [ -n "$PAT" ]; then - REPO="https://x-access-token:${PAT}@github.com/YOUR_USERNAME/YOUR_SOURCE_REPO.git" - fi - git clone --depth 1 --branch main "$REPO" /tmp/source + git clone --depth 1 --branch main \ + https://github.com/ravindu644/Droidspaces-OSS.git /tmp/source rm -rf docs/content/ - cp -r /tmp/source/docs/content docs/content/ + mkdir -p docs/content + cp -r /tmp/source/Documentation/. docs/content/ - name: Build HTML run: python3 .github/scripts/build-docs.py @@ -31,8 +30,13 @@ jobs: - name: Commit and push run: | SHA="${{ github.event.client_payload.sha }}" + if [ -z "$SHA" ]; then + SHA=$(git -C /tmp/source rev-parse HEAD) + fi git config user.name "docs-bot" git config user.email "bot@droidspaces.org" + git remote set-url origin \ + https://x-access-token:${{ github.token }}@github.com/${{ github.repository }}.git git add -A git diff --cached --quiet || \ git commit -m "docs: update from source@${SHA:0:7}" && \ diff --git a/SOURCE_WORKFLOW_REFERENCE.yml b/SOURCE_WORKFLOW_REFERENCE.yml deleted file mode 100644 index 2d1d4df..0000000 --- a/SOURCE_WORKFLOW_REFERENCE.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Place this file in your SOURCE repo at: -# .github/workflows/docs-updated.yml -# -# Replace USERNAME/REPO with the actual source repo path. -# The WEB_REPO_PAT must be a classic PAT with `repo` scope, -# stored as a secret in the source repo's Settings → Secrets → Actions. - -on: - push: - branches: [main] - paths: - - 'docs/content/**' - - 'mkdocs.yml' # optional — trigger on config changes too - -jobs: - dispatch: - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.WEB_REPO_PAT }} - script: | - await github.rest.repos.createDispatchEvent({ - owner: 'droidspaces', - repo: 'droidspaces.github.io', - event_type: 'docs-updated', - client_payload: { - ref: context.ref, - sha: context.sha - } - }); diff --git a/docs/common-errors.html b/docs/common-errors.html deleted file mode 100644 index 7a7bf3d..0000000 --- a/docs/common-errors.html +++ /dev/null @@ -1,631 +0,0 @@ - - - - - - - - Common Errors - Droidspaces Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    - - - - \ No newline at end of file diff --git a/docs/community-supported-devices.html b/docs/community-supported-devices.html index fbb7229..825b60b 100644 --- a/docs/community-supported-devices.html +++ b/docs/community-supported-devices.html @@ -4,15 +4,15 @@ - - Supported Devices - Droidspaces Docs - + + Community-Supported Devices - Droidspaces Docs + - + @@ -64,7 +64,7 @@ .sidebar-content { flex: 1; min-width: 0; padding: 2rem 2rem 4rem; - max-width: 960px; + max-width: none; } .sidebar-content h1 { font-family: var(--mono); font-size: clamp(1.5rem, 2.5vw, 2rem); @@ -95,12 +95,14 @@ .sidebar-content strong { color: var(--text); } .sidebar-content a { color: var(--accent2); text-decoration: none; + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content a:hover { text-decoration: underline; } .sidebar-content code { font-family: var(--mono); font-size: 0.82rem; background: var(--bg3); padding: 0.15rem 0.4rem; border-radius: 4px; color: var(--accent2); + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content pre { background: var(--bg2); border: 1px solid var(--border); @@ -150,13 +152,17 @@ } .table-wrap { overflow-x: auto; + -webkit-overflow-scrolling: touch; margin-bottom: 1.5rem; } .table-wrap table { + width: max-content; + min-width: 100%; margin-bottom: 0; } .sidebar-content table { - width: 100%; border-collapse: collapse; font-size: 0.85rem; + width: max-content; min-width: 100%; + border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1.5rem; } .sidebar-content th { @@ -169,7 +175,8 @@ .sidebar-content td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); - word-break: break-word; + white-space: normal; word-break: normal; + overflow-wrap: break-word; max-width: 300px; } .sidebar-content img { max-width: 100%; border-radius: 8px; border: 1px solid var(--border); @@ -353,7 +360,7 @@ - Docs/Reference/Supported Devices + Docs/Reference/Community-Supported Devices
    @@ -362,17 +369,16 @@ @@ -391,6 +396,9 @@

    Contribution guidelines

    To keep this list useful and reliable, please follow these rules when adding or updating entries:

    -
    ← Common ErrorsNix / NixOS →
    +
    ← TroubleshootingNix/NixOS →
    diff --git a/docs/cool-things-you-can-do.html b/docs/cool-things-you-can-do.html index 5854503..1288cc3 100644 --- a/docs/cool-things-you-can-do.html +++ b/docs/cool-things-you-can-do.html @@ -4,7 +4,7 @@ - + Cool Things You Can Do - Droidspaces Docs @@ -64,7 +64,7 @@ .sidebar-content { flex: 1; min-width: 0; padding: 2rem 2rem 4rem; - max-width: 960px; + max-width: none; } .sidebar-content h1 { font-family: var(--mono); font-size: clamp(1.5rem, 2.5vw, 2rem); @@ -95,12 +95,14 @@ .sidebar-content strong { color: var(--text); } .sidebar-content a { color: var(--accent2); text-decoration: none; + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content a:hover { text-decoration: underline; } .sidebar-content code { font-family: var(--mono); font-size: 0.82rem; background: var(--bg3); padding: 0.15rem 0.4rem; border-radius: 4px; color: var(--accent2); + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content pre { background: var(--bg2); border: 1px solid var(--border); @@ -150,13 +152,17 @@ } .table-wrap { overflow-x: auto; + -webkit-overflow-scrolling: touch; margin-bottom: 1.5rem; } .table-wrap table { + width: max-content; + min-width: 100%; margin-bottom: 0; } .sidebar-content table { - width: 100%; border-collapse: collapse; font-size: 0.85rem; + width: max-content; min-width: 100%; + border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1.5rem; } .sidebar-content th { @@ -169,7 +175,8 @@ .sidebar-content td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); - word-break: break-word; + white-space: normal; word-break: normal; + overflow-wrap: break-word; max-width: 300px; } .sidebar-content img { max-width: 100%; border-radius: 8px; border: 1px solid var(--border); @@ -362,17 +369,16 @@ @@ -393,80 +398,148 @@

    Cool Things You Can Do with Dro
    IMPORTANT This guide is specifically focused on Android devices. While Droidspaces also runs on Linux Desktop, these instructions address the unique networking, storage, and kernel requirements of the Android environment.

    Quick Navigation


    1. Setting Up a Secure "Mobile Server" (Tailscale + UFW + Fail2Ban)

    You can turn your Android device into a secure, accessible-from-anywhere Linux server by combining Droidspaces with Tailscale and standard Linux security tools.

    Prerequisites


    Step 1: Install Networking Tools & Compatibility Layer

    To handle firewall rules and network debugging, you first need to install the essential networking tools and ensure compatibility with the Android kernel.

      -
    1. Install tools:
      apt update && apt install -y net-tools iptables
      -
    2. -
    3. Switch to Legacy iptables:Modern Ubuntu/Debian versions use the nftables backend by default, which often fails in Droidspaces containers on Android kernels. You must switch to the legacy iptables backend to ensure your firewall works:
      update-alternatives --set iptables /usr/sbin/iptables-legacy
      +
    4. Install tools: +
      apt update && apt install -y net-tools iptables
      +
      +
    5. +
    6. Switch to Legacy iptables: +

      Modern Ubuntu/Debian versions use the nftables backend by default, which often fails in Droidspaces containers on Android kernels. You must switch to the legacy iptables backend to ensure your firewall works:

      +
      update-alternatives --set iptables /usr/sbin/iptables-legacy
       update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
      -
    7. +
      +

    Step 2: Personal User Setup & SSH Hardening

    To maintain a secure server, creating a dedicated user with sudo privileges and disabling direct root access over SSH is best practice.

      -
    1. Reclaim UID 1000: Linux distributions usually assign UID 1000 to the first non-root user (like ubuntu). To use this ID for your personal user, you should first detect and completely remove any existing UID 1000:
      # Identify and delete the default user associated with UID 1000
      +
    2. Reclaim UID 1000: Linux distributions usually assign UID 1000 to the first non-root user (like ubuntu). To use this ID for your personal user, you should first detect and completely remove any existing UID 1000: +
      # Identify and delete the default user associated with UID 1000
       DEFAULT_USER=$(getent passwd 1000 | cut -d: -f 1)
       userdel -r "$DEFAULT_USER"
       groupdel "$DEFAULT_USER" 2>/dev/null
      -
    3. -
    4. Create your personal user as UID 1000 (Replace YOUR_USER with your desired username):
      useradd -m -u 1000 -s /bin/bash YOUR_USER
      +
      +
    5. +
    6. Create your personal user as UID 1000 (Replace YOUR_USER with your desired username): +
      useradd -m -u 1000 -s /bin/bash YOUR_USER
       usermod -aG sudo YOUR_USER
       passwd YOUR_USER
      -
    7. -
    8. Install OpenSSH Server:
      apt install -y openssh-server
      -
    9. -
    10. Disable Root Login:Edit /etc/ssh/sshd_config to prevent direct root access:
      sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config
      +
      +
    11. +
    12. Install OpenSSH Server: +
      apt install -y openssh-server
      +
      +
    13. +
    14. Disable Root Login: +

      Edit /etc/ssh/sshd_config to prevent direct root access:

      +
      sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config
       sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
       systemctl restart ssh
      -
    15. +
      +

    Step 3: Set Up Tailscale

    Tailscale provides a secure P2P tunnel to your container, allowing you to access it from any device in your Tailnet without opening ports on your public router.

      -
    1. Install Tailscale:
      curl -fsSL https://tailscale.com/install.sh | sh
      -
    2. -
    3. Authenticate:
      tailscale up
      -
    4. +
    5. Install Tailscale: +
      curl -fsSL https://tailscale.com/install.sh | sh
      +
      +
    6. +
    7. Authenticate: +
      tailscale up
      +
      +

    Step 4: Secure the Container with UFW (Firewall)

    Since Droidspaces NAT mode currently only supports IPv4, we should disable IPv6 in UFW to avoid initialization errors.

      -
    1. Disable IPv6 in UFW:
      sed -i 's/IPV6=yes/IPV6=no/' /etc/default/ufw
      -
    2. -
    3. Set Default Policies:
      ufw default deny incoming
      +
    4. Disable IPv6 in UFW: +
      sed -i 's/IPV6=yes/IPV6=no/' /etc/default/ufw
      +
      +
    5. +
    6. Set Default Policies: +
      ufw default deny incoming
       ufw default allow outgoing
      -
    7. -
    8. Whitelist the Tailscale Interface:Instead of whitelisting specific IP addresses, tell UFW to trust anything coming through your private Tailscale tunnel:
      ufw allow in on tailscale0
      -
    9. -
    10. Enable the Firewall:
      ufw --force enable
      -
    11. +
      +
    12. +
    13. Whitelist the Tailscale Interface: +

      Instead of whitelisting specific IP addresses, tell UFW to trust anything coming through your private Tailscale tunnel:

      +
      ufw allow in on tailscale0
      +
      +
    14. +
    15. Enable the Firewall: +
      ufw --force enable
      +
      +

    Step 5: Add Brute-Force Protection with Fail2Ban

    Fail2Ban monitors your system logs and automatically blocks IP addresses that show malicious behavior.

      -
    1. Install Fail2Ban:
      apt install -y fail2ban
      -
    2. -
    3. Create a Local Configuration:Create a persistent configuration file at /etc/fail2ban/jail.local to protect SSH and integrate it with UFW:
      [DEFAULT]
      +
    4. Install Fail2Ban: +
      apt install -y fail2ban
      +
      +
    5. +
    6. Create a Local Configuration: +

      Create a persistent configuration file at /etc/fail2ban/jail.local to protect SSH and integrate it with UFW:

      +
      [DEFAULT]
       # Ban for 1 hour after 5 failed attempts within 10 minutes
       bantime  = 1h
       findtime = 10m
      @@ -485,10 +558,13 @@ 

      Step 5: Add Brute-Force enabled = true port = ssh backend = systemd -

    7. -
    8. Start and Verify:
      systemctl restart fail2ban
      +
      +
    9. +
    10. Start and Verify: +
      systemctl restart fail2ban
       fail2ban-client status sshd
      -
    11. +
      +

    Your "Mobile Server" is now officially a hardened fortress! Anyone attempting to access it from the open internet will be blocked, while you maintain full access through your private Tailscale network.


    @@ -496,10 +572,18 @@

    2. Running Docker C

    Droidspaces supports running Docker natively inside your containers on all supported kernel versions. This allows you to run nested containerized services (like Portainer, Home Assistant, etc.) directly on your Android device.

    Prerequisites


    Step 1: Ensure NAT Networking

    @@ -546,7 +630,7 @@

    "Last Reso
    WARNING Above daemon.json configuration disables Docker's internal bridge (docker0) and all automatic port forwarding. You will only be able to run docker containers with internet with the --network host flag. eg: docker run -it --network host ubuntu

    -
    ← Linux CLI UsageTroubleshooting →
    +
    ← Linux CLITroubleshooting →
    diff --git a/docs/features.html b/docs/features.html index 341e06f..47b36c4 100644 --- a/docs/features.html +++ b/docs/features.html @@ -4,15 +4,15 @@ - - Features Deep Dive - Droidspaces Docs - + + Feature Deep Dives - Droidspaces Docs + - + @@ -64,7 +64,7 @@ .sidebar-content { flex: 1; min-width: 0; padding: 2rem 2rem 4rem; - max-width: 960px; + max-width: none; } .sidebar-content h1 { font-family: var(--mono); font-size: clamp(1.5rem, 2.5vw, 2rem); @@ -95,12 +95,14 @@ .sidebar-content strong { color: var(--text); } .sidebar-content a { color: var(--accent2); text-decoration: none; + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content a:hover { text-decoration: underline; } .sidebar-content code { font-family: var(--mono); font-size: 0.82rem; background: var(--bg3); padding: 0.15rem 0.4rem; border-radius: 4px; color: var(--accent2); + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content pre { background: var(--bg2); border: 1px solid var(--border); @@ -150,13 +152,17 @@ } .table-wrap { overflow-x: auto; + -webkit-overflow-scrolling: touch; margin-bottom: 1.5rem; } .table-wrap table { + width: max-content; + min-width: 100%; margin-bottom: 0; } .sidebar-content table { - width: 100%; border-collapse: collapse; font-size: 0.85rem; + width: max-content; min-width: 100%; + border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1.5rem; } .sidebar-content th { @@ -169,7 +175,8 @@ .sidebar-content td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); - word-break: break-word; + white-space: normal; word-break: normal; + overflow-wrap: break-word; max-width: 300px; } .sidebar-content img { max-width: 100%; border-radius: 8px; border: 1px solid var(--border); @@ -353,7 +360,7 @@ - Docs/Guides/Features Deep Dive + Docs/Guides/Feature Deep Dives
    @@ -362,17 +369,16 @@ @@ -411,9 +416,12 @@

    What Are Namespaces?

    Network Namespace Isolation (--net)

    Droidspaces supports three networking modes that determine whether a network namespace (CLONE_NEWNET) is used:

      -
    1. Host Mode (--net=host) - Default: Droidspaces deliberately does not unshare the network namespace. The container shares the host's network stack. This greatly simplifies setup: containers get internet access immediately without virtual bridges, NAT, or firewall rules. On Android, where networking is already complex (cellular, Wi-Fi, VPN), this avoids a whole category of connectivity issues.
    2. -
    3. NAT Mode (--net=nat): The container is placed in a private network namespace. It is connected to the host via a virtual bridge or veth pair, providing Pure Network Isolation while maintaining internet access through the host's upstream interfaces. Compatible with the vast majority of Android devices.
    4. -
    5. None Mode (--net=none): The container is placed in a private, air-gapped network namespace with only the loopback interface enabled for maximum security.
    6. +
    7. Host Mode (--net=host) - Default: Droidspaces deliberately does not unshare the network namespace. The container shares the host's network stack. This greatly simplifies setup: containers get internet access immediately without virtual bridges, NAT, or firewall rules. On Android, where networking is already complex (cellular, Wi-Fi, VPN), this avoids a whole category of connectivity issues. +
    8. +
    9. NAT Mode (--net=nat): The container is placed in a private network namespace. It is connected to the host via a virtual bridge or veth pair, providing Pure Network Isolation while maintaining internet access through the host's upstream interfaces. Compatible with the vast majority of Android devices. +
    10. +
    11. None Mode (--net=none): The container is placed in a private, air-gapped network namespace with only the loopback interface enabled for maximum security. +

    How It Compares to Chroot

    A chroot only changes the apparent root directory for a process. It provides no process isolation, no mount isolation, no hostname isolation, and no IPC isolation. Any process inside a chroot shares the host's PID space, can see and signal other processes, and cannot run an init system like systemd.

    @@ -424,27 +432,40 @@

    Why Init Systems Matter

    Without an init system, you're running individual processes in a chroot. You can't manage services, you can't use systemctl, you don't have journald for logging, and you don't have proper session management. It's a glorified shell.

    Droidspaces boots a real init system. When systemd starts as PID 1 inside the container:

      -
    • Services are managed via systemctl start/stop/enable
    • -
    • Logs are available via journalctl
    • -
    • User sessions work properly with login, su, and sudo
    • -
    • Targets and dependencies are resolved correctly
    • -
    • Timer units, socket activation, and all other systemd features work
    • +
    • Services are managed via systemctl start/stop/enable +
    • +
    • Logs are available via journalctl +
    • +
    • User sessions work properly with login, su, and sudo +
    • +
    • Targets and dependencies are resolved correctly +
    • +
    • Timer units, socket activation, and all other systemd features work +

    How Droidspaces Enables It

    Three things are required for systemd to function inside a container:

      -
    1. PID 1: The init process must be PID 1. Droidspaces achieves this with a PID namespace (CLONE_NEWPID) followed by a fork, making the container's init the first process in its namespace.
    2. -
    3. Container detection: Systemd needs to know it's running inside a container. Droidspaces writes droidspaces to /run/systemd/container and sets the container=droidspaces environment variable.
    4. -
    5. Cgroup access: Systemd requires write access to its cgroup hierarchy to create scopes and slices. Droidspaces provides this through per-container cgroup trees (see Cgroup Isolation).
    6. +
    7. PID 1: The init process must be PID 1. Droidspaces achieves this with a PID namespace (CLONE_NEWPID) followed by a fork, making the container's init the first process in its namespace. +
    8. +
    9. Container detection: Systemd needs to know it's running inside a container. Droidspaces writes droidspaces to /run/systemd/container and sets the container=droidspaces environment variable. +
    10. +
    11. Cgroup access: Systemd requires write access to its cgroup hierarchy to create scopes and slices. Droidspaces provides this through per-container cgroup trees (see Cgroup Isolation). +

    Supported Init Systems

    Droidspaces is theoretically compatible with any init system that can run as PID 1, including:

      -
    • systemd (most Linux distributions)
    • -
    • OpenRC (Alpine Linux, Gentoo)
    • -
    • runit (Void Linux, Devuan)
    • -
    • s6-init (Alpine, various containers)
    • -
    • SysVinit (Debian, Devuan)
    • +
    • systemd (most Linux distributions) +
    • +
    • OpenRC (Alpine Linux, Gentoo) +
    • +
    • runit (Void Linux, Devuan) +
    • +
    • s6-init (Alpine, various containers) +
    • +
    • SysVinit (Debian, Devuan) +

    The init binary is strictly expected at /sbin/init. If this binary is missing or not executable, Droidspaces will fail to boot the container to ensure that services and session management function as expected.


    @@ -454,17 +475,24 @@

    What Is Volatile Mode?

    How It Works

    Droidspaces uses OverlayFS, a union filesystem built into the Linux kernel:

      -
    • Lower layer: The original rootfs (mounted read-only if using the rootfs.img mode)
    • -
    • Upper layer: A tmpfs-backed directory that captures all writes
    • -
    • Merged view: The container sees a unified filesystem where reads come from the lower layer and writes go to the upper layer
    • +
    • Lower layer: The original rootfs (mounted read-only if using the rootfs.img mode) +
    • +
    • Upper layer: A tmpfs-backed directory that captures all writes +
    • +
    • Merged view: The container sees a unified filesystem where reads come from the lower layer and writes go to the upper layer +

    When the container stops, the upper layer (in RAM) is discarded. The original rootfs remains untouched.

    Use Cases

      -
    • Testing: Install packages, modify configurations, and verify changes without committing anything
    • -
    • Development: Spin up a clean environment for each build
    • -
    • Security: Guaranteed clean state on every boot
    • -
    • Experimentation: Break things without consequences
    • +
    • Testing: Install packages, modify configurations, and verify changes without committing anything +
    • +
    • Development: Spin up a clean environment for each build +
    • +
    • Security: Guaranteed clean state on every boot +
    • +
    • Experimentation: Break things without consequences +

    Usage

    # Volatile container from a directory
    @@ -490,10 +518,14 @@ 

    The systemd 258+ Fix

    NOTE This information is based on current developer understanding of systemd's behavior in Droidspaces and may require further verification.

    Droidspaces handles this with a "dynamic hole-punching" technique:

      -
    1. Pinning Subsystems: All /sys subdirectories are self-bind-mounted to preserve read-write access to individual hardware subsystems.
    2. -
    3. Read-Only Remount: The top-level /sys is remounted read-only.
    4. -
    5. Container Identification: systemd detects the read-only /sys, correctly identifies the container environment, and falls back to container-native console management.
    6. -
    7. Hardware Access: Individual hardware subsystems remain fully accessible via the pinned sub-mounts created in step 1.
    8. +
    9. Pinning Subsystems: All /sys subdirectories are self-bind-mounted to preserve read-write access to individual hardware subsystems. +
    10. +
    11. Read-Only Remount: The top-level /sys is remounted read-only. +
    12. +
    13. Container Identification: systemd detects the read-only /sys, correctly identifies the container environment, and falls back to container-native console management. +
    14. +
    15. Hardware Access: Individual hardware subsystems remain fully accessible via the pinned sub-mounts created in step 1. +

    Usage

    droidspaces --name=gpu-test --rootfs=/path/to/rootfs --hw-access start
    @@ -501,16 +533,21 @@ 

    Usage

    Automatic GPU Group Setup

    When --hw-access is enabled, Droidspaces automatically:

      -
    1. Scans host GPU devices - Before pivot_root, it probes ~40 known GPU device paths (/dev/dri/*, /dev/mali*, /dev/kgsl-3d0, /dev/nvidia*, etc.) and collects their group IDs via stat(). Dangerous nodes like /dev/dri/card* are explicitly skipped to prevent host kernel panics, as these nodes are restricted to the host's display manager.
    2. -
    3. Creates matching groups - After pivot_root, it appends entries like gpu_:x::root to the container's /etc/group. The container's root user is automatically added to each group.
    4. -
    5. Idempotent restarts - On container restart, existing groups are detected and skipped (no duplicate entries).
    6. +
    7. Scans host GPU devices - Before pivot_root, it probes ~40 known GPU device paths (/dev/dri/*, /dev/mali*, /dev/kgsl-3d0, /dev/nvidia*, etc.) and collects their group IDs via stat(). Dangerous nodes like /dev/dri/card* are explicitly skipped to prevent host kernel panics, as these nodes are restricted to the host's display manager. +
    8. +
    9. Creates matching groups - After pivot_root, it appends entries like gpu_:x::root to the container's /etc/group. The container's root user is automatically added to each group. +
    10. +
    11. Idempotent restarts - On container restart, existing groups are detected and skipped (no duplicate entries). +

    This eliminates the need for manual groupadd/usermod commands inside the container, while ensuring the host's kernel stability by avoiding restricted hardware paths.

    X11 Socket Mounting

    For GUI application support, Droidspaces automatically bind-mounts the X11 socket directory:

      -
    • Android (Termux X11): Detects and mounts /data/data/com.termux/files/usr/tmp/.X11-unix
    • -
    • Desktop Linux: Mounts /tmp/.X11-unix via /proc/1/root/tmp/.X11-unix
    • +
    • Android (Termux X11): Detects and mounts /data/data/com.termux/files/usr/tmp/.X11-unix +
    • +
    • Desktop Linux: Mounts /tmp/.X11-unix via /proc/1/root/tmp/.X11-unix +
    TIP X11 support can be enabled independently using the --termux-x11 (-X) flag. This is the recommended way to use GUI applications on Android if you do not need full GPU/hardware access, as it preserves a higher level of isolation.

    After starting the container, set DISPLAY=:0 inside the container to use the X11 display.

    @@ -551,8 +588,10 @@

    Syntax

    Limits

      -
    • Destination must be an absolute path
    • -
    • Path traversal (..) in destinations is rejected for security
    • +
    • Destination must be an absolute path +
    • +
    • Path traversal (..) in destinations is rejected for security +

    Automatic Directory Creation

    If the destination directory doesn't exist inside the rootfs, Droidspaces creates it automatically using mkdir -p.

    @@ -594,10 +633,14 @@

    Why Use Images?

    How It Works

    When you use --rootfs-img:

      -
    1. Filesystem check: Droidspaces runs e2fsck -f -y on the image to ensure integrity
    2. -
    3. SELinux context: On Android, applies the vold_data_file SELinux context to prevent silent I/O denials
    4. -
    5. Loop mount: The image is mounted at /mnt/Droidspaces/
    6. -
    7. Retry logic: On kernel 4.14, mounts may fail due to stale loop device state. Droidspaces retries up to 3 times with sync() and settle delays.
    8. +
    9. Filesystem check: Droidspaces runs e2fsck -f -y on the image to ensure integrity +
    10. +
    11. SELinux context: On Android, applies the vold_data_file SELinux context to prevent silent I/O denials +
    12. +
    13. Loop mount: The image is mounted at /mnt/Droidspaces/ +
    14. +
    15. Retry logic: On kernel 4.14, mounts may fail due to stale loop device state. Droidspaces retries up to 3 times with sync() and settle delays. +

    Usage

    # Image-based container (--name is mandatory)
    @@ -619,8 +662,10 @@ 

    The "Jail" Trick

    Cgroup v1 and v2 Support

    Droidspaces supports both cgroup versions:

      -
    • Cgroup v2 (unified): Used by modern distributions. Mounted as a single hierarchy.
    • -
    • Cgroup v1 (legacy): Used by older distributions. Droidspaces handles comounted controllers (e.g., cpu,cpuacct) and creates symlinks for secondary names in older kernels or --force-cgroupv1 mode.
    • +
    • Cgroup v2 (unified): Used by modern distributions. Mounted as a single hierarchy. +
    • +
    • Cgroup v1 (legacy): Used by older distributions. Droidspaces handles comounted controllers (e.g., cpu,cpuacct) and creates symlinks for secondary names in older kernels or --force-cgroupv1 mode. +

    Forcing Legacy Cgroup V1 (--force-cgroupv1)

    On legacy Android kernels (3.18, 4.4, or 4.9), the host system may either lack Cgroup v2 support entirely or provide a partial implementation without the essential controllers (CPU, memory, etc.) required by modern systemd. This inconsistency often causes systemd to misidentify the environment, leading to critical boot failures.

    @@ -642,10 +687,73 @@

    Nested Containers (Docker, Podman,
    TIP Legacy Kernel Networking: When running Docker/Podman inside Droidspaces on legacy kernels, modern nftables may fail to route traffic. We recommend using Droidspaces' NAT mode and switching your container's networking stack to iptables-legacy and ip6tables-legacy.

    Android-Specific Tuning

    -

    Droidspaces includes several sophisticated subsystems designed specifically to handle the "opinionated" nature of the Android Linux kernel.

    -

    Safe Udev Trigger

    -

    Standard Linux distributions use udevadm trigger to "coldplug" hardware devices during boot. On many Android devices, triggering all devices simultaneously causes the kernel to deadlock or panic because Android's own hardware drivers (which are already running) do not expect another manager to re-trigger them.

    -

    The Solution: Droidspaces masks the standard udev trigger services and installs a Safe Udev Trigger. This service only triggers a strictly defined subset of subsystems (usb, block, input, tty) that are safe to re-scan. This enables the container to see new USB drives or keyboards without risking a system crash.

    +

    To handle the "opinionated" nature of the Android Linux kernel and ensure container stability, network connectivity, and hardware access, several adjustments must be applied to the container's rootfs.

    +
    NOTE The Droidspaces backend itself does not alter the rootfs. These changes are applied automatically when the user installs a new rootfs tarball using the Android App's built-in installer, or are pre-baked when using our official rootfs tarball from the Droidspaces rootfs-builder.
    +

    1. Android Network & Hardware Groups

    +

    Older Android kernels restrict network socket creation and direct hardware access to specific, hardcoded Group IDs (GIDs). Droidspaces maps and configures these groups inside the container's rootfs:

    +
      +
    • GID Mapping: Appends Android-specific groups to /etc/group: +
        +
      • aid_inet (3003): Allows internet access. +
      • +
      • aid_net_raw (3004): Allows raw socket creation (e.g., for ping). +
      • +
      • aid_net_admin (3005): Allows network administration. +
      • +
      +
    • +
    • Permissions Assignment: Adds the container's root user to the aid_inet, aid_net_raw, input, video, and tty groups. +
    • +
    • Package Manager Fix: Configures the Debian/Ubuntu _apt user to use aid_inet as its primary group, allowing packages to be installed and updated without permission errors. +
    • +
    • User Automation: Modifies /etc/adduser.conf so any newly created user automatically inherits these groups. +
    • +
    +

    2. Udev Trigger & Service Overrides

    +

    Standard Linux distributions run udevadm trigger to coldplug hardware devices during boot. Triggering all subsystems simultaneously on an Android device can cause the kernel to panic.

    +
      +
    • Hardware Access Guards: Since udev services are only useful when hardware access is explicitly enabled, Droidspaces injects a drop-in ExecCondition override that prevents systemd-udevd.service, systemd-udev-trigger.service, and systemd-udev-settle.service from starting unless the container is configured with hardware access (enable_hw_access=1): +
      [Service]
      +ExecCondition=
      +ExecCondition=/bin/sh -c "grep -q 'enable_hw_access=1' /run/droidspaces/container.config"
      +
      +
    • +
    • Safe Udev Trigger: Instead of scanning everything, Droidspaces overrides the default systemd-udev-trigger.service using a drop-in configuration. If hardware access is enabled, this limits the trigger to a strictly defined, safe subset of subsystems: +
      [Service]
      +ExecStart=
      +ExecStart=-/usr/bin/udevadm trigger --subsystem-match=usb --subsystem-match=block --subsystem-match=input --subsystem-match=tty --subsystem-match=net
      +
      +

      This allows the container to dynamically detect new USB drives, keyboards, and network interfaces without risking a host crash.

      +
    • +
    • Read-Only Path Fix: Overrides ConditionPathIsReadWrite for all udev units to prevent failures in environments where key system directories are mounted read-only. +
    • +
    +

    3. Optimizing systemd & Logging

    +

    The Android kernel is notoriously verbose. Without tuning, standard journald setups would read host kernel messages and generate gigabytes of logs, quickly filling up the device's internal storage:

    +
      +
    • Journald Adjustments: Disables reading kernel messages and system auditing (ReadKMsg=no, Audit=no) in journald.conf to prevent the container from hoarding system-wide kernel logs. +
    • +
    • Volatile Storage: Configures systemd journal logs to store in-memory only (Storage=volatile) and enforces strict maximum size constraints (200MB) to prevent constant writes from wearing out and filling the device's physical internal flash storage. +
    • +
    • Service Masking: Masks systemd-networkd-wait-online.service to prevent boot delays, and systemd-journald-audit.socket to prevent systemd deadlocks in old kernels like 4.9. +
    • +
    • Power Key Handling: Instructs systemd-logind to ignore host power and suspend key events so the container does not attempt to handle host power state transitions. +
    • +
    +

    4. NAT Mode Network Guards

    +

    Under Host networking mode, running network managers like NetworkManager or systemd-networkd inside the container can conflict with the Android host's routing tables and break cellular/Wi-Fi connectivity.

    +

    Droidspaces injects a drop-in ExecCondition override for standard network services (such as NetworkManager.service, systemd-networkd.service, dhcpcd.service, and systemd-resolved.service). This ensures these services only execute if the container is explicitly configured in NAT mode:

    +
    [Service]
    +ExecCondition=
    +ExecCondition=/bin/sh -c "grep -q 'net_mode=nat' /run/droidspaces/container.config"
    +
    +

    5. Storage and DHCP Configuration

    +
      +
    • systemd-networkd Config: Automatically configures 10-eth-dhcp.network to enable DHCP and IPv6 route acceptance for any eth* interfaces. +
    • +
    • Logrotate Limit: Enforces a maxsize 50M limit in /etc/logrotate.conf to prevent logs from consuming excessive disk space over time. +
    • +
    diff --git a/docs/getting-started.html b/docs/getting-started.html deleted file mode 100644 index d24d637..0000000 --- a/docs/getting-started.html +++ /dev/null @@ -1,539 +0,0 @@ - - - - - - - - Getting Started - Droidspaces Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - -
    - - - - \ No newline at end of file diff --git a/docs/gpu-acceleration.html b/docs/gpu-acceleration.html index cfb6c1a..1e3daeb 100644 --- a/docs/gpu-acceleration.html +++ b/docs/gpu-acceleration.html @@ -3,17 +3,17 @@ - - + + GPU Acceleration - Droidspaces Docs - + - + @@ -64,7 +64,7 @@ .sidebar-content { flex: 1; min-width: 0; padding: 2rem 2rem 4rem; - max-width: 960px; + max-width: none; } .sidebar-content h1 { font-family: var(--mono); font-size: clamp(1.5rem, 2.5vw, 2rem); @@ -95,12 +95,14 @@ .sidebar-content strong { color: var(--text); } .sidebar-content a { color: var(--accent2); text-decoration: none; + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content a:hover { text-decoration: underline; } .sidebar-content code { font-family: var(--mono); font-size: 0.82rem; background: var(--bg3); padding: 0.15rem 0.4rem; border-radius: 4px; color: var(--accent2); + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content pre { background: var(--bg2); border: 1px solid var(--border); @@ -150,13 +152,17 @@ } .table-wrap { overflow-x: auto; + -webkit-overflow-scrolling: touch; margin-bottom: 1.5rem; } .table-wrap table { + width: max-content; + min-width: 100%; margin-bottom: 0; } .sidebar-content table { - width: 100%; border-collapse: collapse; font-size: 0.85rem; + width: max-content; min-width: 100%; + border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1.5rem; } .sidebar-content th { @@ -169,7 +175,8 @@ .sidebar-content td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); - word-break: break-word; + white-space: normal; word-break: normal; + overflow-wrap: break-word; max-width: 300px; } .sidebar-content img { max-width: 100%; border-radius: 8px; border: 1px solid var(--border); @@ -362,17 +369,16 @@ @@ -393,40 +398,64 @@

    Droidspaces GPU Acceleration GuideThis guide provides step-by-step instructions for enabling GPU acceleration in your Droidspaces containers. Whether you are running on an Android device or a Linux desktop, Droidspaces offers multiple ways to leverage hardware acceleration for a smooth graphical experience.

    Quick Navigation


    Android

    Hardware acceleration on Android is achieved by bridging the container's graphics stack with a host-side X server (Termux-X11). Droidspaces handles the complex mount management and security contexts required to make this seamless.

    -
    TIP If you want to enjoy an out-of-the-box XFCE desktop environment experience, you can download our pre-configured XFCE tarballs from the official Droidspaces Rootfs Builder Releases.
    +
    TIP If you want to enjoy an out-of-the-box XFCE desktop environment experience, you can download our pre-configured XFCE tarballs from the Rootfs repository or from the official Droidspaces Rootfs Builder Releases.

    01. Termux-X11 + llvmpipe

    This method uses software rendering via llvmpipe. While it doesn't provide full hardware acceleration, it is the most stable way to run GUI applications when a compatible GPU driver isn't available.

    The "Unified Tmpfs Bridge"

    When you enable the Termux X11 toggle in the Droidspaces app, the following sequence occurs:

      -
    1. Host-side Preparation: Droidspaces creates a tmpfs mount on top of Termux's /data/data/com.termux/files/usr/tmp in the host's mount namespace.
    2. -
    3. Bypassing FBE Encryption: While a direct bind-mount of /data/data/com.termux/files/usr/tmp to the container is possible, it frequently breaks applications like apt or any tool performing heavy I/O in /tmp. This happens because Termux's data directory is protected by Android's File-Based Encryption (FBE), leading to "Required key not available" (ENOKEY) errors. By bridging the path via tmpfs, X11 sockets and temporary files become fully readable and writable by the container.
    4. -
    5. Bind Mounting: This "Unified Tmpfs Bridge" is then bind-mounted to the container's /tmp directory, enabling seamless communication between the container and the Termux-X11 app.
    6. +
    7. Host-side Preparation: Droidspaces creates a tmpfs mount on top of Termux's /data/data/com.termux/files/usr/tmp in the host's mount namespace. +
    8. +
    9. Bypassing FBE Encryption: While a direct bind-mount of /data/data/com.termux/files/usr/tmp to the container is possible, it frequently breaks applications like apt or any tool performing heavy I/O in /tmp. This happens because Termux's data directory is protected by Android's File-Based Encryption (FBE), leading to "Required key not available" (ENOKEY) errors. By bridging the path via tmpfs, X11 sockets and temporary files become fully readable and writable by the container. +
    10. +
    11. Bind Mounting: This "Unified Tmpfs Bridge" is then bind-mounted to the container's /tmp directory, enabling seamless communication between the container and the Termux-X11 app. +

    Setup Requirements

      -
    • Termux: pkg install x11-repo && pkg install termux-x11
    • -
    • Container: sudo apt install mesa-utils (for testing with glxgears)
    • +
    • Termux: pkg install x11-repo && pkg install termux-x11 +
    • +
    • Container: sudo apt install mesa-utils (for testing with glxgears) +

    Implementation Steps

      -
    1. Configure Container: In the Droidspaces app, navigate to your container's configuration.
    2. -
    3. Enable X11: Toggle Termux-X11 to ON (Hardware Access is not required for software rendering).
    4. -
    5. Environment: Add DISPLAY=:0 to the Environment Variables section and save.
    6. -
    7. Start Container: Launch your container.
    8. -
    9. Launch X Server: Open the Termux app and run:
      termux-x11 :0
      -
    10. -
    11. Verify: Run glxgears inside the container terminal. The output will render in the Termux-X11 app.
    12. -
    13. Start Desktop Environment: To launch the full XFCE desktop (if installed), run:
      dbus-launch --exit-with-session startxfce4
      -
    14. +
    15. Configure Container: In the Droidspaces app, navigate to your container's configuration. +
    16. +
    17. Enable X11: Toggle Termux-X11 to ON (Hardware Access is not required for software rendering). +
    18. +
    19. Environment: Add DISPLAY=:0 to the Environment Variables section and save. +
    20. +
    21. Start Container: Launch your container. +
    22. +
    23. Launch X Server: Open the Termux app and run: +
      termux-x11 :0
      +
      +
    24. +
    25. Verify: Run glxgears inside the container terminal. The output will render in the Termux-X11 app. +
    26. +
    27. Start Desktop Environment: To launch the full XFCE desktop (if installed), run: +
      dbus-launch --exit-with-session startxfce4
      +
      +

    @@ -434,22 +463,34 @@

    02. Termux-X11 + VirGL

    This method provides GPU acceleration for non-Qualcomm devices (Mali/PowerVR) via a virglrenderer bridge. It translates OpenGL calls from the container into commands that the host Android OS can execute.

    Setup Requirements

      -
    • Termux: pkg install x11-repo && pkg install termux-x11 virglrenderer-android
    • -
    • Container: sudo apt install mesa-utils (for testing with glxgears)
    • +
    • Termux: pkg install x11-repo && pkg install termux-x11 virglrenderer-android +
    • +
    • Container: sudo apt install mesa-utils (for testing with glxgears) +

    Implementation Steps

      -
    1. Container Configuration: Enable Termux-X11 in the Droidspaces container settings. Then, add the following to the Environment Variables section:
      DISPLAY=:0
      +
    2. Container Configuration: Enable Termux-X11 in the Droidspaces container settings. Then, add the following to the Environment Variables section: +
      DISPLAY=:0
       GALLIUM_DRIVER=virpipe
      -
    3. -
    4. Start Container: Launch your container.
    5. -
    6. Start VirGL Server: Open Termux and run the server in the background:
      virgl_test_server_android &
      -
    7. -
    8. Start X Server: In Termux, run:
      termux-x11 :0
      -
    9. -
    10. Verify Acceleration: Run glxinfo -B and look for "VirGL" in the renderer string.
    11. -
    12. Start Desktop Environment: To launch the full XFCE desktop (if installed), run:
      dbus-launch --exit-with-session startxfce4
      -
    13. +
      +
    14. +
    15. Start Container: Launch your container. +
    16. +
    17. Start VirGL Server: Open Termux and run the server in the background: +
      virgl_test_server_android &
      +
      +
    18. +
    19. Start X Server: In Termux, run: +
      termux-x11 :0
      +
      +
    20. +
    21. Verify Acceleration: Run glxinfo -B and look for "VirGL" in the renderer string. +
    22. +
    23. Start Desktop Environment: To launch the full XFCE desktop (if installed), run: +
      dbus-launch --exit-with-session startxfce4
      +
      +
    TIP If the renderer fails to initialize, try starting the VirGL server with the Vulkan backend: virgl_test_server_android --angle-vulkan &
    @@ -459,21 +500,38 @@

    03. Turnip (Native Qualcomm/Adreno)

    For Qualcomm Adreno GPUs, Droidspaces supports native hardware acceleration using the Turnip driver. This bypasses the need for virgl and provides near-native performance.

    Requirements

    Implementation Steps

      -
    1. Install the custom Mesa driver from the Mesa for Android Container repository.
    2. -
    3. Enable GPU Access: In the container settings, enable GPU Access and Termux X11.
    4. -
    5. Set Display: Add DISPLAY=:0 to your environment variables.
    6. -
    7. Launch Sequence:- Start the container via Droidspaces.- Open Termux and run termux-x11 :0
    8. -
    9. Permission Management (Non-Root Users):If you are using a non-root user, you must grant them access to the GPU device nodes:
      sudo usermod -aG droidspaces-gpu 
      -
    10. -
    11. Start Desktop Environment: To launch the full XFCE desktop (if installed), run:
      dbus-launch --exit-with-session startxfce4
      -
    12. +
    13. Install the custom Mesa driver from the Mesa for Android Container repository. +
    14. +
    15. Enable GPU Access: In the container settings, enable GPU Access and Termux X11. +
    16. +
    17. Set Display: Add DISPLAY=:0 to your environment variables. +
    18. +
    19. Launch Sequence: +
        +
      • Start the container via Droidspaces. +
      • +
      • Open Termux and run termux-x11 :0 +
      • +
      +
    20. +
    21. Permission Management (Non-Root Users): +

      If you are using a non-root user, you must grant them access to the GPU device nodes:

      +
      sudo usermod -aG droidspaces-gpu 
      +
      +
    22. +
    23. Start Desktop Environment: To launch the full XFCE desktop (if installed), run: +
      dbus-launch --exit-with-session startxfce4
      +
      +
    -
    TIP If you encounter any problems related to DRI3, try editing /data/adb/modules/droidspaces/etc/droidspaces.te and uncommenting the line: +
    TIP If you encounter any problems related to DRI3, try editing /data/adb/modules/droidspaces/sepolicy.rule and uncommenting the line: allow untrusted_app_27 droidspacesd fd use

    @@ -481,19 +539,27 @@

    Linux Desktop (AMD/Intel)

    On Linux-based hosts, GPU acceleration works natively with zero additional configuration within Droidspaces.

    Requirements

      -
    • An active X11 or Wayland session on your host.
    • -
    • Functional GPU drivers (Mesa/Intel/AMD).
    • +
    • An active X11 or Wayland session on your host. +
    • +
    • Functional GPU drivers (Mesa/Intel/AMD). +

    Implementation Steps

      -
    1. Enable Hardware Access: Ensure the Hardware Access toggle is enabled in your container configuration (or use the --hw-access CLI flag).
    2. -
    3. Xhost Permission: On your host machine, allow the container to connect to your X server:
      xhost +local:
      -
    4. -
    5. Set Display Variable: Add the host's DISPLAY number to the container's environment (usually :0):
      echo "DISPLAY=:0" >> /etc/environment
      -
    6. -
    7. Run Applications: GUI applications launched from the container will render natively with full hardware acceleration.
    8. +
    9. Enable Hardware Access: Ensure the Hardware Access toggle is enabled in your container configuration (or use the --hw-access CLI flag). +
    10. +
    11. Xhost Permission: On your host machine, allow the container to connect to your X server: +
      xhost +local:
      +
      +
    12. +
    13. Set Display Variable: Add the host's DISPLAY number to the container's environment (usually :0): +
      echo "DISPLAY=:0" >> /etc/environment
      +
      +
    14. +
    15. Run Applications: GUI applications launched from the container will render natively with full hardware acceleration. +
    - +
    diff --git a/docs/index.html b/docs/index.html index ca610cc..89da0fc 100644 --- a/docs/index.html +++ b/docs/index.html @@ -4,11 +4,11 @@ Documentation - Droidspaces - - - + + + -

    Redirecting to Getting Started...

    +

    Redirecting to Installation...

    diff --git a/docs/installation-android.html b/docs/installation-android.html index 947e96c..f162019 100644 --- a/docs/installation-android.html +++ b/docs/installation-android.html @@ -4,7 +4,7 @@ - + Android Installation - Droidspaces Docs @@ -64,7 +64,7 @@ .sidebar-content { flex: 1; min-width: 0; padding: 2rem 2rem 4rem; - max-width: 960px; + max-width: none; } .sidebar-content h1 { font-family: var(--mono); font-size: clamp(1.5rem, 2.5vw, 2rem); @@ -95,12 +95,14 @@ .sidebar-content strong { color: var(--text); } .sidebar-content a { color: var(--accent2); text-decoration: none; + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content a:hover { text-decoration: underline; } .sidebar-content code { font-family: var(--mono); font-size: 0.82rem; background: var(--bg3); padding: 0.15rem 0.4rem; border-radius: 4px; color: var(--accent2); + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content pre { background: var(--bg2); border: 1px solid var(--border); @@ -150,13 +152,17 @@ } .table-wrap { overflow-x: auto; + -webkit-overflow-scrolling: touch; margin-bottom: 1.5rem; } .table-wrap table { + width: max-content; + min-width: 100%; margin-bottom: 0; } .sidebar-content table { - width: 100%; border-collapse: collapse; font-size: 0.85rem; + width: max-content; min-width: 100%; + border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1.5rem; } .sidebar-content th { @@ -169,7 +175,8 @@ .sidebar-content td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); - word-break: break-word; + white-space: normal; word-break: normal; + overflow-wrap: break-word; max-width: 300px; } .sidebar-content img { max-width: 100%; border-radius: 8px; border: 1px solid var(--border); @@ -362,17 +369,16 @@ @@ -393,36 +398,74 @@

    Android Installation Guide

    Droidspaces on Android is designed to be a "Zero Terminal" experience. From the first install to running a full Linux distribution, everything is handled through the intuitive Android app.

    Prerequisites

      -
    1. Rooted device with supported rooting solutions from here
    2. -
    3. Compatible kernel with Droidspaces support enabled (see Kernel Configuration Guide)
    4. +
    5. Rooted device with supported rooting solutions from here +
    6. +
    7. Compatible kernel with Droidspaces support enabled (see Kernel Configuration Guide) +

    Step 1: Install the App

      -
    1. Download the Droidspaces APK from the latest release.
    2. -
    3. Install the APK on your device.
    4. -
    5. Grant root access and open the app.
    6. +
    7. Download the Droidspaces APK from the latest release. +
    8. +
    9. Install the APK on your device. +
    10. +
    11. Grant root access and open the app. +

    Step 2: Automatic Backend Setup

    On the first launch, Droidspaces performs an Atomic Installation of the backend system: - It detects your device architecture (aarch64, armhf, etc.). - It extracts the droidspaces and busybox binaries to /data/local/Droidspaces/bin. - It performs an atomic move to ensure the binaries are installed correctly even if an older version is currently running. - It verifies checksums to ensure zero corruption.

    Step 3: Setting Up Your First Container

    -

    You don't need to manually extract rootfs files. The app handles it:

    +

    You don't need to manually extract rootfs files. The app handles it all.

    + +

    The easiest way to get started. The app can browse, download, and install distros directly - no manual downloading required.

      -
    1. Download a rootfs tarball: We recommend using our official rootfs tarballs - which are specifically optimized for Android - or the official Linux Containers images.
    2. -
    3. Open the Containers Tab: Tap the middle icon in the bottom navigation bar.
    4. -
    5. Add a Container: Tap the "+" button at the bottom right.
    6. -
    7. Choose your Tarball: Select the downloaded .tar.xz or .tar.gz file.
    8. -
    9. Configuration Wizard:- Name: Give your container a friendly name.- Features: Toggle Hardware Access, IPv6, Network Isolation, Android storage integration, etc., according to your needs.- Container Type: We recommend Sparse Image for better performance and stability on Android’s f2fs storage, as well as to prevent weird SELinux/Keyring issues.
    10. -
    11. Installation: The app will extract the tarball and apply Post-Extraction Fixes automatically (DNS, Masking useless/dangerous services, and Safe Udev).
    12. +
    13. Open the Containers Tab: Tap the middle icon in the bottom navigation bar. +
    14. +
    15. Open the Repository: Tap the cloud icon (above the "+" button). This opens the Rootfs Repository sheet, which automatically fetches all available distros optimized for Android from our official repository. +
    16. +
    17. Pick a distro: Browse or search the list. Each card shows the distro name, size, architecture, and build date. +
    18. +
    19. Download: Tap Download on the distro you want. A progress bar appears on the card. The file saves to your Downloads folder. +
    20. +
    21. Install: Once complete, the button changes to Install. Tap it to launch the container setup wizard. +
    22. +
    23. Configuration Wizard: +
        +
      • Name: Give your container a friendly name. +
      • +
      • Features: Toggle Hardware Access, IPv6, Network Isolation, Android storage integration, etc., according to your needs. +
      • +
      • Container Type: We recommend Sparse Image for better performance and stability on Android’s f2fs storage, as well as to prevent weird SELinux/Keyring issues. +
      • +
      +
    24. +
    25. Done: The app extracts the tarball and automatically applies Post-Extraction Fixes (DNS, masking useless/dangerous services, and Safe Udev). +
    26. +
    +
    TIP The official repository includes distros pre-configured for Android. For a wider selection, you can add the LXC images mirror as a custom repository - see the Rootfs Repository section of the Usage Guide.
    +

    Option B: Install from a Local Tarball

    +

    If you already have a .tar.xz or .tar.gz rootfs file on your device:

    +
      +
    1. Open the Containers Tab and tap the "+" button. +
    2. +
    3. Select your tarball from storage. +
    4. +
    5. Follow the same Configuration Wizard steps above. +
    +
    NOTE Both methods lead to the same wizard - the only difference is where the tarball comes from.

    Verification & Settings

    You can verify your system status at any time: 1. Go to Settings (gear icon) -> Requirements. 2. Tap Check Requirements. This runs the full droidspaces check suite internally. 3. Kernel Config: If you're a kernel developer, you can find a copyable droidspaces.config defconfig fragment, similar to this page, to make sure your kernel is perfectly compatible with Droidspaces.

    Next Steps

    - +
    diff --git a/docs/installation-linux.html b/docs/installation-linux.html index f795723..525e446 100644 --- a/docs/installation-linux.html +++ b/docs/installation-linux.html @@ -4,7 +4,7 @@ - + Linux Installation - Droidspaces Docs @@ -64,7 +64,7 @@ .sidebar-content { flex: 1; min-width: 0; padding: 2rem 2rem 4rem; - max-width: 960px; + max-width: none; } .sidebar-content h1 { font-family: var(--mono); font-size: clamp(1.5rem, 2.5vw, 2rem); @@ -95,12 +95,14 @@ .sidebar-content strong { color: var(--text); } .sidebar-content a { color: var(--accent2); text-decoration: none; + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content a:hover { text-decoration: underline; } .sidebar-content code { font-family: var(--mono); font-size: 0.82rem; background: var(--bg3); padding: 0.15rem 0.4rem; border-radius: 4px; color: var(--accent2); + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content pre { background: var(--bg2); border: 1px solid var(--border); @@ -150,13 +152,17 @@ } .table-wrap { overflow-x: auto; + -webkit-overflow-scrolling: touch; margin-bottom: 1.5rem; } .table-wrap table { + width: max-content; + min-width: 100%; margin-bottom: 0; } .sidebar-content table { - width: 100%; border-collapse: collapse; font-size: 0.85rem; + width: max-content; min-width: 100%; + border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1.5rem; } .sidebar-content th { @@ -169,7 +175,8 @@ .sidebar-content td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); - word-break: break-word; + white-space: normal; word-break: normal; + overflow-wrap: break-word; max-width: 300px; } .sidebar-content img { max-width: 100%; border-radius: 8px; border: 1px solid var(--border); @@ -362,17 +369,16 @@ @@ -437,26 +442,38 @@

    Option A: Use a Directory Rootfs

    Encapsulating your rootfs in a single .img file provides better portability and avoids host filesystem conflicts.

      -
    1. Create a sparse image file (e.g., 16GB):
      truncate -s 16G rootfs.img
      -
    2. -
    3. Format it as ext4:
      mkfs.ext4 -L Droidspaces rootfs.img
      -
    4. -
    5. Mount the image:
      mkdir -p rootfs_mount
      +
    6. Create a sparse image file (e.g., 16GB): +
      truncate -s 16G rootfs.img
      +
      +
    7. +
    8. Format it as ext4: +
      mkfs.ext4 -L Droidspaces rootfs.img
      +
      +
    9. +
    10. Mount the image: +
      mkdir -p rootfs_mount
       sudo mount rootfs.img rootfs_mount
      -
    11. -
    12. Extract the rootfs tarball to the mountpoint:
      sudo tar -xvf /path/to/rootfs.tar.xz -C rootfs_mount
      -
    13. -
    14. Unmount and clean up:
      sudo umount rootfs_mount
      +
      +
    15. +
    16. Extract the rootfs tarball to the mountpoint: +
      sudo tar -xvf /path/to/rootfs.tar.xz -C rootfs_mount
      +
      +
    17. +
    18. Unmount and clean up: +
      sudo umount rootfs_mount
       rmdir rootfs_mount
      -
    19. +
      +

    Now you can boot it instantly using: sudo droidspaces --name=my-container --rootfs-img=rootfs.img start

    Next Steps

    - +
    diff --git a/docs/kernel-configuration.html b/docs/kernel-configuration.html index 790c119..9b9abbc 100644 --- a/docs/kernel-configuration.html +++ b/docs/kernel-configuration.html @@ -3,17 +3,17 @@ - - + + Kernel Configuration - Droidspaces Docs - + - + @@ -64,7 +64,7 @@ .sidebar-content { flex: 1; min-width: 0; padding: 2rem 2rem 4rem; - max-width: 960px; + max-width: none; } .sidebar-content h1 { font-family: var(--mono); font-size: clamp(1.5rem, 2.5vw, 2rem); @@ -95,12 +95,14 @@ .sidebar-content strong { color: var(--text); } .sidebar-content a { color: var(--accent2); text-decoration: none; + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content a:hover { text-decoration: underline; } .sidebar-content code { font-family: var(--mono); font-size: 0.82rem; background: var(--bg3); padding: 0.15rem 0.4rem; border-radius: 4px; color: var(--accent2); + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content pre { background: var(--bg2); border: 1px solid var(--border); @@ -150,13 +152,17 @@ } .table-wrap { overflow-x: auto; + -webkit-overflow-scrolling: touch; margin-bottom: 1.5rem; } .table-wrap table { + width: max-content; + min-width: 100%; margin-bottom: 0; } .sidebar-content table { - width: 100%; border-collapse: collapse; font-size: 0.85rem; + width: max-content; min-width: 100%; + border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1.5rem; } .sidebar-content th { @@ -169,7 +175,8 @@ .sidebar-content td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); - word-break: break-word; + white-space: normal; word-break: normal; + overflow-wrap: break-word; max-width: 300px; } .sidebar-content img { max-width: 100%; border-radius: 8px; border: 1px solid var(--border); @@ -362,17 +369,16 @@ @@ -396,13 +401,20 @@

    Kernel Configuration Guide


    Quick Navigation


    Overview

    @@ -447,8 +459,9 @@

    Step 1: Mandatory Configuration

    # Overlay filesystem support (required for volatile mode) CONFIG_OVERLAY_FS=y -# Enable xattr support on tmpfs -# (required for NixOS setcap wrappers in /run/wrappers) +# Enable xattr, posix acl support on tmpfs +# For NixOS support +CONFIG_TMPFS_POSIX_ACL=y CONFIG_TMPFS_XATTR=y # Firmware loading support @@ -520,9 +533,12 @@

    Step 3: Apply Patches

    Step 4: Build, Flash and Test

      -
    1. Save the configuration blocks above as .config fragments or merge them into your defconfig.
    2. -
    3. Compile and flash the kernel to your device.
    4. -
    5. Verify using the Droidspaces app Settings -> Requirements -> Check Requirements.
    6. +
    7. Save the configuration blocks above as .config fragments or merge them into your defconfig. +
    8. +
    9. Compile and flash the kernel to your device. +
    10. +
    11. Verify using the Droidspaces app Settings -> Requirements -> Check Requirements. +

    Configuring GKI Kernels

    @@ -533,18 +549,21 @@

    Step 1: Apply the Mandatory kAB
    IMPORTANT These patches are NOT OPTIONAL. You MUST apply the correct kABI fix patches for your kernel version. Skipping these patches will cause an immediate bootloop upon enabling CONFIG_SYSVIPC, CONFIG_IPC_NS or CONFIG_POSIX_MQUEUE.

    For ALL Kernels BELOW 6.12 (5.4, 5.10, 5.15, 6.1, 6.6):

    TIP The 001.GKI-below-6.12-fix_sysvipc_kABI_6_7_8.patch is recommended. If this patch causes a bootloop, try the alternative patches from the same folder (e.g., 1_2_3 or 3_4_5).

    For Kernels 5.10 and BELOW ONLY:

    -

    assets/resources/kernel-patches/GKI/below-kernel-6.12/002.5.10_or_lower_use_android_abi_padding_for_posix_mqueue.patch

    For Kernels 6.12 and ABOVE:

    How to apply the patches:

    # Apply each required patch for your kernel version
    @@ -568,11 +587,11 @@ 

    Step 2: Edit gki_defconfig

    # HW Access Support CONFIG_DEVTMPFS=y -# --- Below configs are optional but recommended --- - -# Networking (Docker/NAT support) +# Networking (Enhanced NAT support) CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y +# --- Below configs are optional but recommended --- + # UFW support CONFIG_NETFILTER_XT_TARGET_REJECT=y CONFIG_NETFILTER_XT_TARGET_LOG=y @@ -584,8 +603,9 @@

    Step 2: Edit gki_defconfig

    CONFIG_IP_SET_HASH_NET=y CONFIG_NETFILTER_XT_SET=y -# Enable xattr support on tmpfs -# (required for NixOS setcap wrappers in /run/wrappers) +# Enable xattr, posix acl support on tmpfs +# For NixOS support +CONFIG_TMPFS_POSIX_ACL=y CONFIG_TMPFS_XATTR=y

    Workflow Rules: - Do not append this as a block at the end of the file. - Search for each option individually. - If an option appears as # CONFIG_NAME is not set, change it to CONFIG_NAME=y. - If an option is already set to CONFIG_NAME=y, leave it alone. - If an option does not exist, add it at the end.

    @@ -598,24 +618,37 @@

    Step 4: Flash and Test

    Testing Your Kernel

    1. Run the Requirements Check

      -
    • In the app: Go to Settings (gear icon) -> Requirements -> Check Requirements.
    • -
    • In a terminal: Run:
    • +
    • In the app: Go to Settings (gear icon) -> Requirements -> Check Requirements. +
    • +
    • In a terminal: Run: +
    su -c droidspaces check
     

    This checks for:

      -
    • Root access
    • -
    • Kernel version (minimum 3.18)
    • -
    • PID, MNT, UTS, IPC namespaces
    • -
    • Network namespace (optional, required for NAT/None modes)
    • -
    • Cgroup namespace (optional, for modern cgroup isolation)
    • -
    • devtmpfs support
    • -
    • OverlayFS support (optional, for volatile mode)
    • -
    • VETH and Bridge support (optional, for NAT mode)
    • -
    • PTY/devpts support
    • -
    • Loop device support
    • -
    • ext4 support
    • +
    • Root access +
    • +
    • Kernel version (minimum 3.18) +
    • +
    • PID, MNT, UTS, IPC namespaces +
    • +
    • Network namespace (optional, required for NAT/None modes) +
    • +
    • Cgroup namespace (optional, for modern cgroup isolation) +
    • +
    • devtmpfs support +
    • +
    • OverlayFS support (optional, for volatile mode) +
    • +
    • VETH and Bridge support (optional, for NAT mode) +
    • +
    • PTY/devpts support +
    • +
    • Loop device support +
    • +
    • ext4 support +

    2. Understanding the Results

    @@ -665,16 +698,22 @@

    Nested Containers (Docker, Podman, LXC)

    Legacy Kernel Considerations (4.19 and below)

    Legacy kernels may present some challenges for modern nested container tools:

      -
    • Deadlock Shield trade-off: If your device is affected by the 4.14.113 grab_super() VFS deadlock and requires the Deadlock Shield to boot systemd, enabling the shield will also block the namespace syscalls that Docker, LXC, and Podman need. You cannot use nested containers while the shield is active.
    • -
    • Networking incompatibilities: Modern Docker, LXC, and Podman rely on nftables. Legacy kernels often lack full nftables support. To work around this, use Droidspaces in NAT mode and switch your container's iptables alternative to iptables-legacy and ip6tables-legacy.
    • -
    • BPF conflicts: Modern Docker and runc use BPF_CGROUP_DEVICE for device management. Legacy kernels do not support the required BPF attach types, which causes Invalid argument errors. To work around this, configure Docker to use the cgroupfs driver and the vfs storage driver.
    • +
    • Deadlock Shield trade-off: If your device is affected by the 4.14.113 grab_super() VFS deadlock and requires the Deadlock Shield to boot systemd, enabling the shield will also block the namespace syscalls that Docker, LXC, and Podman need. You cannot use nested containers while the shield is active. +
    • +
    • Networking incompatibilities: Modern Docker, LXC, and Podman rely on nftables. Legacy kernels often lack full nftables support. To work around this, use Droidspaces in NAT mode and switch your container's iptables alternative to iptables-legacy and ip6tables-legacy. +
    • +
    • BPF conflicts: Modern Docker and runc use BPF_CGROUP_DEVICE for device management. Legacy kernels do not support the required BPF attach types, which causes Invalid argument errors. To work around this, configure Docker to use the cgroupfs driver and the vfs storage driver. +

    Additional Resources

    @@ -362,17 +369,16 @@ @@ -629,9 +634,12 @@

    7. System Requirements


    Next Steps

    @@ -362,17 +369,16 @@ @@ -422,7 +427,7 @@

    Finix (no more systemd) (experimenta

    To build a Finix tarball:

    nix build github:ravindu644/Droidspaces-OSS#finixDroidspacesTarballs.aarch64-linux.experimental
     
    - +

    diff --git a/docs/troubleshooting.html b/docs/troubleshooting.html index 87bdec6..761504c 100644 --- a/docs/troubleshooting.html +++ b/docs/troubleshooting.html @@ -4,7 +4,7 @@ - + Troubleshooting - Droidspaces Docs @@ -64,7 +64,7 @@ .sidebar-content { flex: 1; min-width: 0; padding: 2rem 2rem 4rem; - max-width: 960px; + max-width: none; } .sidebar-content h1 { font-family: var(--mono); font-size: clamp(1.5rem, 2.5vw, 2rem); @@ -95,12 +95,14 @@ .sidebar-content strong { color: var(--text); } .sidebar-content a { color: var(--accent2); text-decoration: none; + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content a:hover { text-decoration: underline; } .sidebar-content code { font-family: var(--mono); font-size: 0.82rem; background: var(--bg3); padding: 0.15rem 0.4rem; border-radius: 4px; color: var(--accent2); + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content pre { background: var(--bg2); border: 1px solid var(--border); @@ -150,13 +152,17 @@ } .table-wrap { overflow-x: auto; + -webkit-overflow-scrolling: touch; margin-bottom: 1.5rem; } .table-wrap table { + width: max-content; + min-width: 100%; margin-bottom: 0; } .sidebar-content table { - width: 100%; border-collapse: collapse; font-size: 0.85rem; + width: max-content; min-width: 100%; + border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1.5rem; } .sidebar-content th { @@ -169,7 +175,8 @@ .sidebar-content td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); - word-break: break-word; + white-space: normal; word-break: normal; + overflow-wrap: break-word; max-width: 300px; } .sidebar-content img { max-width: 100%; border-radius: 8px; border: 1px solid var(--border); @@ -362,17 +369,16 @@ @@ -393,22 +398,38 @@

    Troubleshooting

    Common issues, their causes, and how to fix them.

    Quick Navigation


    Modern Distros (Arch, Fedora, etc.) Failure on Legacy Kernels

    @@ -448,12 +469,18 @@

    Container Name Conflicts

    Symptoms: Starting a container fails because a container with the same name is already running, or PID file conflicts occur.

    Solution:

      -
    1. Check what's currently running:
      droidspaces show
      -
    2. -
    3. If the container is listed but you believe it's actually stopped, clean up stale state:
      droidspaces scan
      -
    4. -
    5. Use a different name:
      droidspaces --name=mycontainer-2 --rootfs=/path/to/rootfs start
      -
    6. +
    7. Check what's currently running: +
      droidspaces show
      +
      +
    8. +
    9. If the container is listed but you believe it's actually stopped, clean up stale state: +
      droidspaces scan
      +
      +
    10. +
    11. Use a different name: +
      droidspaces --name=mycontainer-2 --rootfs=/path/to/rootfs start
      +
      +

    Systemd Hangs on Older Kernels

    @@ -479,18 +506,22 @@

    Symptoms: You have no internet access inside the container. Even basic commands like ping fail immediately with a socket: permission denied error, even when running as root.

    Cause: This is caused by Android Paranoid Networking, a security feature found in many Android kernels (especially version 4.14 and older). Unlike standard Linux, the Android kernel restricts network socket creation to specific supplementary Group IDs (GIDs). Without these specific IDs, the kernel's security hooks block the process:

      -
    • AID_INET (3003): Required to create any AF_INET/AF_INET6 socket. Without this, connect() and bind() calls fail.
    • -
    • AID_NET_RAW (3004): Required for ping and other raw networking tasks.
    • -
    • AID_NET_ADMIN (3005): Required for network configuration and routing tasks.
    • +
    • AID_INET (3003): Required to create any AF_INET/AF_INET6 socket. Without this, connect() and bind() calls fail. +
    • +
    • AID_NET_RAW (3004): Required for ping and other raw networking tasks. +
    • +
    • AID_NET_ADMIN (3005): Required for network configuration and routing tasks. +

    Solutions:

      -
    • Kernel Level Fix: If you are building your own kernel, the most effective solution is to disable this restriction entirely in your kernel configuration:
    • -
    +
  • Kernel Level Fix: If you are building your own kernel, the most effective solution is to disable this restriction entirely in your kernel configuration:
    CONFIG_ANDROID_PARANOID_NETWORK=n
     
    -
      -
    • Userland Fix: Use a rootfs that has been specifically patched to include these Android-specific GIDs in the group database. Our official rootfs tarballs come pre-configured to handle these permission requirements:Droidspaces-rootfs-builder Releases
    • + +
    • Userland Fix: Use a rootfs that has been specifically patched to include these Android-specific GIDs in the group database. Our official rootfs tarballs come pre-configured to handle these permission requirements: +

      Droidspaces-rootfs-builder Releases

      +

    DNS / Name Resolution Issues

    @@ -498,9 +529,12 @@

    DNS / Name Resolution Issues

    Cause: It seems some ISPs don’t like custom DNS setups. They completely block common DNS servers like 8.8.8.8 and 1.1.1.1.

    Solution: Use your ISP’s own DNS servers instead of custom ones.

      -
    1. Run this command in an Android root shell to get the default DNS addresses your ISP assigned:
      dumpsys connectivity | sed 's/}}/\n/g' | grep 'InterfaceName: wlan0' | grep -o 'DnsAddresses: \[[^]]*\]' | grep -o '/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' | tr -d '/'
      -
    2. -
    3. Add the results as DNS servers by editing the container configuration in the Droidspaces app.
    4. +
    5. Run this command in an Android root shell to get the default DNS addresses your ISP assigned: +
      dumpsys connectivity | sed 's/}}/\n/g' | grep 'InterfaceName: wlan0' | grep -o 'DnsAddresses: \[[^]]*\]' | grep -o '/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' | tr -d '/'
      +
      +
    6. +
    7. Add the results as DNS servers by editing the container configuration in the Droidspaces app. +

    WiFi/Mobile Data Disconnects

    @@ -508,9 +542,18 @@

    WiFi/Mobile Data Disconnects

    Cause: The container's systemd-networkd service may conflict with Android's network management or attempt to override host-side network configurations.

    Solutions:

      -
    • If you are using the host networking mode: Mask the systemd-networkd service inside the container to prevent it from starting:1. Via Android App: Go to Panel -> Container Name -> Manage (Systemd Menu) and find systemd-networkd, then tap on 3 dot icon next to the systemd-networkd card and select Mask.2. Via Terminal:
      sudo systemctl mask systemd-networkd
      -
    • -
    • Use isolated NAT mode for maximum networking freedom without any conflicts to the host's networking.
    • +
    • If you are using the host networking mode: Mask the systemd-networkd service inside the container to prevent it from starting: +
        +
      1. Via Android App: Go to Panel -> Container Name -> Manage (Systemd Menu) and find systemd-networkd, then tap on 3 dot icon next to the systemd-networkd card and select Mask. +
      2. +
      3. Via Terminal: +
        sudo systemctl mask systemd-networkd
        +
        +
      4. +
      +
    • +
    • Use isolated NAT mode for maximum networking freedom without any conflicts to the host's networking. +

    SELinux-Induced Rootfs Corruption (Directory Mode)

    @@ -526,10 +569,14 @@

    Systemd Service San

    Cause: Modern service files often use advanced systemd sandboxing directives (PrivateTmp, ProtectSystem, RestrictNamespaces). On legacy kernels (3.18 - 4.19), Droidspaces' Adaptive Seccomp Shield intercepts these namespace-related syscalls and returns EPERM to prevent kernel deadlocks. However, some distributions' versions of systemd treat these errors as fatal and refuse to start the service.

    Solution: Create a service override to disable the conflicting sandboxing features:

      -
    1. Identify the service: e.g., redis-server
    2. -
    3. Create the override:
      sudo systemctl edit 
      -
    4. -
    5. Add these lines (to the empty space provided by the editor):
      [Service]
      +
    6. Identify the service: e.g., redis-server +
    7. +
    8. Create the override: +
      sudo systemctl edit 
      +
      +
    9. +
    10. Add these lines (to the empty space provided by the editor): +
      [Service]
       # Disable problematic security sandboxing
       PrivateTmp=no
       PrivateDevices=no
      @@ -539,10 +586,13 @@ 

      Systemd Service San MemoryDenyWriteExecute=no NoNewPrivileges=no CapabilityBoundingSet= -

    11. -
    12. Reload and restart:
      sudo systemctl daemon-reload
      +
      +
    13. +
    14. Reload and restart: +
      sudo systemctl daemon-reload
       sudo systemctl restart 
      -
    15. +
      +

    Reclaiming Storage (Sparse Image)

    @@ -550,10 +600,14 @@

    Reclaiming Storage (Sparse Image)

    Cause: Ext4 sparse images expand as you write data, but the host filesystem cannot automatically detect when blocks are freed inside the image. This is especially common on legacy kernels (e.g., 4.14).

    Solution: Use fstrim inside the container to tell the kernel to "discard" unused blocks, which punches holes in the sparse image and reclaims space on the physical disk.

      -
    1. Start the container normally.
    2. -
    3. Run fstrim as root inside the container:
      sudo fstrim -av
      -
    4. -
    5. The command will report how many bytes were trimmed. You will notice the rootfs.img size on your Android storage has now decreased to match the actual data usage.
    6. +
    7. Start the container normally. +
    8. +
    9. Run fstrim as root inside the container: +
      sudo fstrim -av
      +
      +
    10. +
    11. The command will report how many bytes were trimmed. You will notice the rootfs.img size on your Android storage has now decreased to match the actual data usage. +

    @@ -634,13 +688,18 @@

    3. Wire Up the Init Service

    Getting Help

    If your issue isn't listed here:

      -
    1. Run droidspaces check and note any failures
    2. -
    3. Check the container logs: droidspaces --name=mycontainer run journalctl -n 100
    4. -
    5. Try starting in foreground mode for more visibility: droidspaces --name=mycontainer --rootfs=/path/to/rootfs --foreground start
    6. -
    7. Join the Telegram channel for community support
    8. -
    9. Open an issue on the GitHub repository
    10. +
    11. Run droidspaces check and note any failures +
    12. +
    13. Check the container logs: droidspaces --name=mycontainer run journalctl -n 100 +
    14. +
    15. Try starting in foreground mode for more visibility: droidspaces --name=mycontainer --rootfs=/path/to/rootfs --foreground start +
    16. +
    17. Join the Telegram channel for community support +
    18. +
    19. Open an issue on the GitHub repository +
    - + diff --git a/docs/uninstallation.html b/docs/uninstallation.html index 8c29141..b3dc007 100644 --- a/docs/uninstallation.html +++ b/docs/uninstallation.html @@ -4,7 +4,7 @@ - + Uninstallation - Droidspaces Docs @@ -64,7 +64,7 @@ .sidebar-content { flex: 1; min-width: 0; padding: 2rem 2rem 4rem; - max-width: 960px; + max-width: none; } .sidebar-content h1 { font-family: var(--mono); font-size: clamp(1.5rem, 2.5vw, 2rem); @@ -95,12 +95,14 @@ .sidebar-content strong { color: var(--text); } .sidebar-content a { color: var(--accent2); text-decoration: none; + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content a:hover { text-decoration: underline; } .sidebar-content code { font-family: var(--mono); font-size: 0.82rem; background: var(--bg3); padding: 0.15rem 0.4rem; border-radius: 4px; color: var(--accent2); + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content pre { background: var(--bg2); border: 1px solid var(--border); @@ -150,13 +152,17 @@ } .table-wrap { overflow-x: auto; + -webkit-overflow-scrolling: touch; margin-bottom: 1.5rem; } .table-wrap table { + width: max-content; + min-width: 100%; margin-bottom: 0; } .sidebar-content table { - width: 100%; border-collapse: collapse; font-size: 0.85rem; + width: max-content; min-width: 100%; + border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1.5rem; } .sidebar-content th { @@ -169,7 +175,8 @@ .sidebar-content td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); - word-break: break-word; + white-space: normal; word-break: normal; + overflow-wrap: break-word; max-width: 300px; } .sidebar-content img { max-width: 100%; border-radius: 8px; border: 1px solid var(--border); @@ -362,17 +369,16 @@ @@ -395,25 +400,47 @@

    Uninstallation Guide

    Android (App)

    Follow these steps to ensure all container data and backend files are removed.

      -
    1. Stop Containers: Ensure all running containers are stopped from the Containers tab.
    2. -
    3. Delete Containers:- Go to the Containers tab.- Long-press each container card and select Uninstall Container. This deletes the rootfs image and its configuration.
    4. -
    5. Remove Backend Data:- Using a root file manager or a terminal (like Termux with root access), delete the following directory:
      su -c "rm -rf /data/local/Droidspaces"
      -
    6. -
    7. Uninstall APK: Uninstall the Droidspaces app from your Android settings or launcher.
    8. -
    9. Reboot: Disable or remove the Magisk/KernelSU Droidspaces: Run-at-boot module from your root manager, then reboot to clear any remaining Droidspaces stuff.
    10. +
    11. Stop Containers: Ensure all running containers are stopped from the Containers tab. +
    12. +
    13. Delete Containers: +
        +
      • Go to the Containers tab. +
      • +
      • Long-press each container card and select Uninstall Container. This deletes the rootfs image and its configuration. +
      • +
      +
    14. +
    15. Remove Backend Data: +
        +
      • Using a root file manager or a terminal (like Termux with root access), delete the following directory: +
      • +
      +
      su -c "rm -rf /data/local/Droidspaces"
      +
      +
    16. +
    17. Uninstall APK: Uninstall the Droidspaces app from your Android settings or launcher. +
    18. +
    19. Reboot: Disable or remove the Magisk/KernelSU Droidspaces: Run-at-boot module from your root manager, then reboot to clear any remaining Droidspaces stuff. +

    Linux (CLI)

      -
    1. Stop Containers: Stop all running containers.
      sudo droidspaces --name=web,db stop
      -
    2. -
    3. Remove Filesystem: Delete the Droidspaces workspace directory. This will remove stale PID files, and logs.
      sudo rm -rf /var/lib/Droidspaces
      -
    4. -
    5. Remove Binary: Delete the droidspaces binary.
      sudo rm /usr/local/bin/droidspaces
      +
    6. Stop Containers: Stop all running containers. +
      sudo droidspaces --name=web,db stop
      +
      +
    7. +
    8. Remove Filesystem: Delete the Droidspaces workspace directory. This will remove stale PID files, and logs. +
      sudo rm -rf /var/lib/Droidspaces
      +
      +
    9. +
    10. Remove Binary: Delete the droidspaces binary. +
      sudo rm /usr/local/bin/droidspaces
       # Or wherever you installed it
      -
    11. +
      +
    - + diff --git a/docs/usage-android-app.html b/docs/usage-android-app.html index ad49487..d614b33 100644 --- a/docs/usage-android-app.html +++ b/docs/usage-android-app.html @@ -4,7 +4,7 @@ - + Android App Usage - Droidspaces Docs @@ -64,7 +64,7 @@ .sidebar-content { flex: 1; min-width: 0; padding: 2rem 2rem 4rem; - max-width: 960px; + max-width: none; } .sidebar-content h1 { font-family: var(--mono); font-size: clamp(1.5rem, 2.5vw, 2rem); @@ -95,12 +95,14 @@ .sidebar-content strong { color: var(--text); } .sidebar-content a { color: var(--accent2); text-decoration: none; + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content a:hover { text-decoration: underline; } .sidebar-content code { font-family: var(--mono); font-size: 0.82rem; background: var(--bg3); padding: 0.15rem 0.4rem; border-radius: 4px; color: var(--accent2); + word-break: break-word; overflow-wrap: anywhere; } .sidebar-content pre { background: var(--bg2); border: 1px solid var(--border); @@ -150,13 +152,17 @@ } .table-wrap { overflow-x: auto; + -webkit-overflow-scrolling: touch; margin-bottom: 1.5rem; } .table-wrap table { + width: max-content; + min-width: 100%; margin-bottom: 0; } .sidebar-content table { - width: 100%; border-collapse: collapse; font-size: 0.85rem; + width: max-content; min-width: 100%; + border-collapse: collapse; font-size: 0.85rem; margin-bottom: 1.5rem; } .sidebar-content th { @@ -169,7 +175,8 @@ .sidebar-content td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); - word-break: break-word; + white-space: normal; word-break: normal; + overflow-wrap: break-word; max-width: 300px; } .sidebar-content img { max-width: 100%; border-radius: 8px; border: 1px solid var(--border); @@ -362,17 +369,16 @@ @@ -393,35 +398,79 @@

    Android App Usage Guide

    The Droidspaces Android app provides a premium GUI for managing Linux containers. It abstracts away the complexity of namespaces and mounts while giving you high-level control over your environments.

    Bottom Navigation

      -
    • Home: A dashboard displaying the number of installed and running containers, root availability status, and the backend version.
    • -
    • Containers: A dedicated manager for all installed containers (Install, Start, Stop, Edit, and Uninstall).
    • -
    • Panel: A central dashboard for managing Running Containers and monitoring real-time System Statistics (CPU, RAM, Temperature, etc.).
    • +
    • Home: A dashboard displaying the number of installed and running containers, root availability status, and the backend version. +
    • +
    • Containers: A dedicated manager for all installed containers (Install, Start, Stop, Edit, and Uninstall). +
    • +
    • Panel: A central dashboard for managing Running Containers and monitoring real-time System Statistics (CPU, RAM, Temperature, etc.). +

    Containers Tab

    This tab allows you to install containers using the "+" icon, and lists all your installed environments. Each container has a control card:

      -
    • Install Button (+): Install a new container.
    • -
    • Play Button: Start the container and boot the init system.
    • -
    • Stop Button: Sends a graceful shutdown signal to the container's init.
    • -
    • Cycle Button: Fast-restart the container.
    • -
    • Terminal Icon (Logs): Provides access to persistent session logs for the container's previous start, stop, and restart sequences.
    • +
    • Install Button (+): Install a new container. +
    • +
    • Play Button: Start the container and boot the init system. +
    • +
    • Stop Button: Sends a graceful shutdown signal to the container's init. +
    • +
    • Cycle Button: Fast-restart the container. +
    • +
    • Terminal Icon (Logs): Provides access to persistent session logs for the container's previous start, stop, and restart sequences. +
    -
    TIP You can edit container configuration or uninstall existing installed containers by pressing and holding the container's card. Also gives you the ability to migrate to a rootfs.img-based container or resize your existing rootfs.img..!
    +
    TIP You can edit container configuration or uninstall existing installed containers by pressing and holding the container’s card. Also gives you the ability to migrate to a rootfs.img-based container or resize your existing rootfs.img..!
    +
    +

    Rootfs Repository

    +

    The cloud icon above the "+" button opens the Rootfs Repository - a built-in distro browser that lets you download and install Linux rootfs images without leaving the app.

    +

    How it works

    +
      +
    1. Tap the cloud icon in the Containers tab. +
    2. +
    3. The sheet opens and loads available distros from the Droidspaces official repository. Only images matching your device’s architecture are shown. +
    4. +
    5. Search the list by name, description, or author using the search bar. +
    6. +
    7. Tap Download on a distro card. A progress bar tracks the download; the file is saved to your Downloads folder. +
    8. +
    9. Once done, the button switches to Install. Tap it to go straight into the container setup wizard. +
    10. +
    +
    NOTE If a download fails, the card shows a Retry button. Previously downloaded files are detected automatically on relaunch - the Install button will already be available.
    +

    Adding Custom Repositories

    +

    The repository supports third-party rootfs sources in the same JSON format.

    +
      +
    1. Tap the settings icon (left of the refresh icon) in the sheet header. +
    2. +
    3. Enter a name and a URL pointing to a valid rootfs.json. +
    4. +
    5. Tap Add, then Save. The sheet refreshes and merges results from all sources. +
    6. +
    +
    TIP To get a much wider selection of distros, add the official LXC images mirror as a custom repository: +- Name: anything you like (e.g. LXC Mirror) +- URL: https://raw.githubusercontent.com/Droidspaces/linuxcontainers-mirror/refs/heads/main/rootfs.json

    Networking Configuration

    When editing or creating a container, you can choose from three networking modes:

      -
    • Host (Default): Shares host network directly.
    • -
    • NAT (Isolated): Private network namespace with deterministic IP and port forwarding support.
    • -
    • None: No network access.
    • +
    • Host (Default): Shares host network directly. +
    • +
    • NAT (Isolated): Private network namespace with deterministic IP and port forwarding support. +
    • +
    • None: No network access. +

    Configuring Upstream Interfaces (NAT Mode)

    If you select NAT (Isolated) mode, you must specify one or more upstream interfaces for the container to have internet access. The app provides a convenient auto-detection workflow:

      -
    1. Detect Wi-Fi: Connect to your Wi-Fi network and press the refresh button in the "Upstream Interfaces" menu. Select the interface (usually wlan0) that appears.
    2. -
    3. Detect Mobile Data: Disable Wi-Fi and connect to mobile data. Press the refresh button again and select the mobile data interface (e.g., rmnet0, ccmni1).
    4. -
    5. Save: Both interfaces will now be used by the Route Monitor to keep your container connected as you switch networks.
    6. +
    7. Detect Wi-Fi: Connect to your Wi-Fi network and press the refresh button in the "Upstream Interfaces" menu. Select the interface (usually wlan0) that appears. +
    8. +
    9. Detect Mobile Data: Disable Wi-Fi and connect to mobile data. Press the refresh button again and select the mobile data interface (e.g., rmnet0, ccmni1). +
    10. +
    11. Save: Both interfaces will now be used by the Route Monitor to keep your container connected as you switch networks. +
    TIP You can manually enter wildcards in the Upstream Interfaces list (e.g., rmnet*) to ensure connectivity even if your carrier cycles through different interface names (like rmnet_data0 and rmnet_data1).
    NOTE NAT mode is IPv4 only. If your carrier only provides IPv6, see the IPv4 NAT Workaround.
    @@ -438,26 +487,37 @@

    Accessing the Container Shell

    Method 1: Built-in Terminal (v5.7.0+)

    This is the most convenient way to quickly run commands without leaving the Droidspaces app.

      -
    1. Ensure the container is RUNNING.
    2. -
    3. Navigate to the Panel tab and tap the container to open its Details.
    4. -
    5. Find the Terminal card and tap Open.
    6. -
    7. Select the User you wish to log in as (e.g., root or your default user).
    8. -
    9. An interactive terminal will launch directly within the app.
    10. +
    11. Ensure the container is RUNNING. +
    12. +
    13. Navigate to the Panel tab and tap the container to open its Details. +
    14. +
    15. Find the Terminal card and tap Open. +
    16. +
    17. Select the User you wish to log in as (e.g., root or your default user). +
    18. +
    19. An interactive terminal will launch directly within the app. +

    Method 2: External Terminal (Copy Login)

    For power users who prefer Termux, ADB, or other terminal emulators, Droidspaces allows you to "attach" external sessions to the container.

      -
    1. Ensure the container is RUNNING.
    2. -
    3. Open the container Details in the Panel tab.
    4. -
    5. Select your desired user from the dropdown menu.
    6. -
    7. Tap Copy Login. This copies a command like su -c 'droidspaces --name=[name enter [user]' to your clipboard.
    8. -
    9. Open your preferred terminal (e.g., Termux) and Paste the command.
    10. -
    11. Run the command (ensure your terminal has root permissions granted from your root manager).
    12. +
    13. Ensure the container is RUNNING. +
    14. +
    15. Open the container Details in the Panel tab. +
    16. +
    17. Select your desired user from the dropdown menu. +
    18. +
    19. Tap Copy Login. This copies a command like su -c 'droidspaces --name=[name enter [user]' to your clipboard. +
    20. +
    21. Open your preferred terminal (e.g., Termux) and Paste the command. +
    22. +
    23. Run the command (ensure your terminal has root permissions granted from your root manager). +

    Settings & Requirements

    Accessed via the gear icon in the top right: - Requirements: Runs a 27-point diagnostic check on your kernel. - Kernel Config: Provides a copyable droidspaces.config snippet specifically for your device. - Theme Engine: Support for AMOLED Black, Material You, Changing accent colors, and Light/Dark modes.

    - + diff --git a/downloads.html b/downloads.html index 10f17a7..2c31618 100644 --- a/downloads.html +++ b/downloads.html @@ -70,20 +70,20 @@
    -

    v6.2.0

    -

    Released Date: 2026-05-22

    +

    v6.2.5

    +

    Released Date: 2026-05-29

    Android

    APK for rooted Android devices. KernelSU, Magisk, or APatch.

    - Download APK + Download APK

    Linux

    Static tarball for any Linux distribution. Zero dependencies.

    - Download Tarball + Download Tarball
    @@ -118,85 +118,153 @@

    Download kernel patches

    -

    v6.2.0

    +

    v6.2.5

    What's Changed

      -
    • fix(terminal): resolve hostname before opening tabs/picker (588cca1)
    • -
    • fix(terminal/panel): unified OSInfo stream eliminates hostname/metrics null bug (cb5cdd2)
    • -
    • droidspaces: bump v6.2.0 (823b889)
    • -
    • Translated using Weblate (#144) (4c37545)
    • -
    • fix: prevent UI remount and terminal state loss on screen rotation (cc491fd)
    • -
    • fix(service): update terminal session notification count and localize strings (f8088a5)
    • -
    • post_extract_fixes: configure systemd-networkd for eth0 and restrict network services to NAT mode via ExecCondition (2ae320c)
    • -
    • Merge branch 'dev' (16a7b39)
    • -
    • fix: correct banner printing order in start and restart flows (2b700a1)
    • -
    • app: scale up Ubuntu logo (6bb6669)
    • -
    • nix: modularize code, keep API intact, add pinned systemd v257, improve rootfs module (#143) (6e535c1)
    • -
    • app: add Azure icon support and map Azure and Mariner strings to IconUtils (b2ec2c6)
    • -
    • ui: Change default network mode to NAT and update static IP description (03c4bec)
    • -
    • socketd: preserve image-backed rootfs references in container summaries (#142) (b908c72)
    • -
    • config: implement semantic comparison to prevent redundant config writes (5ecb630)
    • -
    • Merge branch 'dev' (1363f5e)
    • -
    • Merge branch 'main' into dev (aa89854)
    • -
    • boot: guard UUID marker write against empty uuid (aba9b80)
    • -
    • app: preserve UUID across container config edits; parse uuid in parseConfig() (cf9cd1b)
    • -
    • pid: add collect_active_uuids(); container: skip generate_uuid() if existing UUID is collision-free (5fe67cc)
    • -
    • nix: add minimal-with-systemd-v257 (#141) (d20e6f1)
    • -
    • nix: fix android app drv that previously did not include binaries (#140) (f571bb2)
    • -
    • mount: skip tty1-N null symlinks in privileged+unfiltered-dev mode (b0acd95)
    • -
    • docs: update contributing guidelines to include Linux support, platform detection, and strict submission requirements (7a9e778)
    • -
    • docs: add CONTRIBUTING.md with project philosophy and submission guidelines (0d4d660)
    • -
    • seccomp: block host clock modification syscalls (39fb8de)
    • -
    • Merge branch 'main' into dev (f4c9277)
    • -
    • utils: harden init detection for Nix-based and wrapper-script rootfs (3ef14b2)
    • -
    • docs: we hit the 400KB binary size limit :( (b0f8ad5)
    • -
    • docs: added RISC-V 64 support to the supported architectures (4c045b9)
    • -
    • docs: remove deprecated UI credits for KernelSU-Next, MMRL, and LSPatch from README (68a873c)
    • -
    • docs: rewrote Droidspaces comparison sections into a comprehensive table against alternatives (1300228)
    • -
    • droidspaces.te: fixed a typo (5c4f40c)
    • -
    • Merge pull request #138 from yoshi3jp/web (8716a9c)
    • -
    • Translated using Weblate (Romanian) (#139) (3127eeb)
    • -
    • docs: add XFCE launch instructions and fix typos in SELinux policy documentation (e522f70)
    • -
    • nix: add nix documentation (#137) (2b19080)
    • -
    • socketd: replace snapshot dummies with backend-backed JSON projections (53df9e7)
    • -
    • socketd: add typed backend client methods for snapshot data (f99a8be)
    • -
    • socketd: add core lifecycle event journal and polling opcode (3e7ce18)
    • -
    • socketd: add backend pseudo-image inventory opcode (47be2d2)
    • -
    • socketd: add backend info counters for container inventory (c71485a)
    • -
    • socketd: implement backend container inventory opcode (93053ad)
    • -
    • Merge pull request #133 from yoshi3jp/web (cf823ca)
    • -
    • Merge branch 'main' into dev (4690c7f)
    • -
    • socketd: satisfy Portainer snapshot probes and expose local events (8d13720)
    • -
    • socketd: add dummy container list endpoint for Portainer probing (8f2baf4)
    • -
    • socketd: expose initial TCP Docker-compatible discovery API (709f5cd)
    • -
    • Translated using Weblate (Chinese (Simplified Han script)) (#136) (bf38753)
    • -
    • nix: ignore power/suspend key events in logind (#135) (9308fa2)
    • -
    • fixup boot module version and versionCode (2885999)
    • -
    • Nix: Fixing rootfs config, update nixpkgs, support for finix (#134) (347754e)
    • -
    • Web API skeleton (#132) (4131127)
    • -
    • fix(icons): clear OS info cache on container uninstall (1ccfc66)
    • -
    • feat(icons): prefetch distro icon on container start, cache forever, apply to all 3 card locations (141843e)
    • -
    • feat(ui): synchronize container installer options and enhance UI consistency (3e3b027)
    • -
    • ui: unify distro icon fetching and clear stale cache on stop/restart (f402152)
    • -
    • feat(ui): add custom icons for 22 popular Linux distributions in container details (cfe0c7e)
    • -
    • ui: fix real-time IP updates and prevent stale data display on restart (802524a)
    • -
    • virt: fix frozen/drifting uptime across all kernel versions (c04446c)
    • -
    • Merge branch 'main' into dev (b0871d5)
    • -
    • Translated using Weblate (Chinese (Traditional Han script)) (#131) (91089e6)
    • -
    • app: add support for configuring a custom init binary for containers (5a4cf94)
    • -
    • boot: add --init=PATH to override the default init binary (de4e15d)
    • -
    • virt: decouple resource visibility from cgroup limits (59160a4)
    • -
    • System-wide init family awareness (#129) (1660f6e)
    • -
    • Merge branch 'main' into dev (ff42b09)
    • -
    • cgroup: disable virtualization when controllers are unavailable (fe3553c)
    • -
    • feat: add [VIRT] prefix support to message logging filter (c455b09)
    • -
    • feat(virt): implement resource visibility virtualization (9802718)
    • -
    • cgroup: implement resource constraints via v2 delegation (84c4ca7)
    • -
    • [daemon] add optional backend bridge for future socket API service (#110) (59e53d6)
    • -
    • Add OnePlus SM8650(LineageOS) to community support devices list (#125) (e770d6f)
    • -
    • Add Nothing Phone (1) to supported devices list (#126) (f5b557e)
    • +
    • fix: bump boot module version to v6.2.5 (65e8011) +
    • +
    • docs: update XFCE tarball resource links and fix formatting for DRI3 tip (e64b269) +
    • +
    • docs: update installation and usage guides to include Rootfs Repository features (afb16a3) +
    • +
    • docs: update gallery and showcase screenshots in readme (8c2be2d) +
    • +
    • droidspaces: v6.2.5 (be2dbc2) +
    • +
    • Translated using Weblate (#165) (0efdc4c) +
    • +
    • seccomp: drop mknod/mknodat device blocking (580c1ea) +
    • +
    • post_extract_fixes: generate and set machine-id to prevent systemd deadlocks on Fedora 44 (8645ce1) +
    • +
    • post_extract_fixes: remove problematic iptables service files (2a30f3c) +
    • +
    • Add conditional compilation for ds_socketd_record_core_event (924a3c1) +
    • +
    • build: reduce R8 obfuscation to lower AV heuristic score (8de6bcc) +
    • +
    • fix: declare BootReceiver to satisfy RECEIVE_BOOT_COMPLETED permission (9d1ff64) +
    • +
    • fix: remove shadowed context variable in ContainerCard (1be8b50) +
    • +
    • docs: zh-CN: move language switcher to the top of README (01ff26c) +
    • +
    • fix: distro icons disappearing after app kill (d9d6bd5) +
    • +
    • mount: fix /proc/sys RW holes being clobbered by parent RO lock (2c1cf81) +
    • +
    • refactor: rename clean_kmsg.txt to last_kmsg.txt for consistency in bug report collection (7291aa3) +
    • +
    • daemon: add mid-run log rotation for droidspacesd.log (3805da1) +
    • +
    • ds_dhcp: fix cross-container DHCP leaks with ifindex and direction filtering (7964783) +
    • +
    • style: enforce consistent code formatting using clang-format across source files (fffaa78) +
    • +
    • build: fix all hardened-debug compiler warnings (f1ae0ef) +
    • +
    • log: persist container logging across pivot_root isolation (ba51ef9) +
    • +
    • virtualize.c: add pre-check to skip virtualization updates if tmpfs directory is missing (2c2b6bf) +
    • +
    • mount: unify masking as self-bind+RO, drop unused shared mask-dir tmpfs (29ae5da) +
    • +
    • feat: wire read-only bind mount flag to app (9c60d95) +
    • +
    • mount: add :ro flag support for read-only bind mounts (7b97ff3) +
    • +
    • Translated using Weblate (#163) (b615530) +
    • +
    • More Shortened titles in Docs metadata (#162) (62e6306) +
    • +
    • Shortened titles in Docs metadata (#161) (921b99d) +
    • +
    • docs: move language switcher to the top of README (eb721a0) +
    • +
    • post_extract_fixes: do not add ExecCondition to udev-related units (136ec2f) +
    • +
    • fix: post_extract_fixes: guard udev socket units with hardware access limit (0d504ad) +
    • +
    • ui: polish rootfs repository sheet and fix cosmetic bugs (a3cdcec) +
    • +
    • Update translation files (#157) (2bbe25c) +
    • +
    • app: Rootfs Repository: use unique, metadata-derived filenames for rootfs assets to prevent download conflicts (c73586d) +
    • +
    • Android: fix icon cache poisoning and stale state after container poweroff (b626078) +
    • +
    • seccomp: truly skip all filters when noseccomp is active (0ea180e) +
    • +
    • nix: finix: fix finix using wrong arch. improve compatibility with droidspaces (#159) (01ce155) +
    • +
    • docs: zh-CN: consolidate Simplified Chinese translations into singular folder (a5746c7) +
    • +
    • Simplified Chinese Translation of Document (#158) (c931c5b) +
    • +
    • app: Rootfs Repository: contextual empty state and hide banner while searching (009e08e) +
    • +
    • app: Rootfs Repository: filter rootfs assets based on detected device architecture (f81a350) +
    • +
    • app: add custom rootfs repo support (d98185a) +
    • +
    • docs: add trailing spaces to markdown quick navigation lists for improved rendering (6629f0a) +
    • +
    • docs: add disclaimer warning to community-supported devices documentation (6ab10fa) +
    • +
    • fix: cancel terminal session notification upon service termination or empty session state (a5baa69) +
    • +
    • fix: add hostname sanitization and validation for container configuration menu (7c91bcf) +
    • +
    • app: Rootfs Repository: fix rootfs downloads saving with display name instead of filename (9b21332) +
    • +
    • app: removed unused strings (17c979c) +
    • +
    • app: add open-source repository banner to rootfs sheet (3e5f74b) +
    • +
    • app: Rootfs Repository: replace download count with build_date from JSON (c3c68a2) +
    • +
    • app: Rootfs Repository: adapt to new rootfs.json format (ecbffac) +
    • +
    • fix: prevent Linux /dev breakage by restricting device pruning to Android environments (21ab8dc) +
    • +
    • fix: nuke container sessions before stop/restart (58b5973) +
    • +
    • post_extract_fixes: restrict dhcpcd to NAT mode and whitelist eth interfaces to prevent Android network interference (b6c5cbc) +
    • +
    • post_extract_fixes/docs: gate udev services behind hardware access config and update documentation (2d9c389) +
    • +
    • Translated using Weblate (#153) (1f00fbb) +
    • +
    • app: fix cancel button not stopping DownloadManager download (dac54d4) +
    • +
    • Added docs dispatch workflow to trigger web repo on Documentation changes (#156) (ef2dc4a) +
    • +
    • Added metatags to Documentation (#155) (7dcbf04) +
    • +
    • Correct model number for two devices (#154) (a8f6100) +
    • +
    • app: use overflow-driven font auto-shrink for rootfs asset card names (544e358) +
    • +
    • app: implement rootfs repository browser and download manager for rootfs tarballs (65a042a) +
    • +
    • app: add support for OpenRC init system management in the container info menu (d336534) +
    • +
    • docs: added oppo reno10 devices to GKI support list (#152) (34a68b2) +
    • +
    • docs: added Oneplus SM8250 devices to Non-GKI support list (#151) (5358ec6) +
    • +
    • Translated using Weblate (Khmer (Central), Portuguese) (#150) (ee10cc8) +
    • +
    • requirements: update kernel configuration to include TMPFS_POSIX_ACL and reorganize networking settings (9ab49f7) +
    • +
    • Add machine-readable output support to show command (7c4864f) +
    • +
    • docs: Fix duplicated 'https://' and format chart (#148) (5aeb895) +
    • +
    • docs: Update 5.10 GKI community supported devices (#147) (6220539) +

    Automated Release by Droidspaces CI

    @@ -210,10 +278,10 @@

    What's Changed

    Previous releases

    -
  • +
    VersionDate
    Droidspaces v6.1.52026-05-15Download
    + - -
    VersionDate
    Droidspaces v6.2.02026-05-22Download
    Droidspaces v6.1.52026-05-15Download
    Musl Toolchains to compile Droidspaces2026-05-14Download
    Droidspaces v6.1.02026-05-13Download
    Droidspaces v6.0.02026-04-24Download
    +Droidspaces v6.1.02026-05-13Download diff --git a/index.html b/index.html index be8a734..de8fe2e 100644 --- a/index.html +++ b/index.html @@ -62,7 +62,7 @@ "Material 3 management app with built-in terminal" ], "fileSize": "400KB", - "softwareVersion": "6.1.5", + "softwareVersion": "6.2.5", "license": "https://github.com/ravindu644/Droidspaces-OSS/blob/main/LICENSE", "sameAs": [ "https://github.com/ravindu644/Droidspaces-OSS", @@ -141,7 +141,7 @@
    -
    v6.1.5 · Open Source
    +
    v6.2.5 · Open Source

    Linux containers
    on @@ -159,7 +159,7 @@

    diff --git a/sitemap.xml b/sitemap.xml index 37bd626..3b6be08 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -18,17 +18,11 @@ monthly 0.1 - - https://www.droidspaces.org/docs/getting-started.html - 2026-05-23 - monthly - 0.9 - https://www.droidspaces.org/docs/installation-android.html 2026-05-23 monthly - 0.8 + 0.9 https://www.droidspaces.org/docs/installation-linux.html @@ -72,12 +66,6 @@ monthly 0.6 - - https://www.droidspaces.org/docs/common-errors.html - 2026-05-23 - monthly - 0.6 - https://www.droidspaces.org/docs/troubleshooting.html 2026-05-23 diff --git a/style.css b/style.css index c7b9413..109acd9 100644 --- a/style.css +++ b/style.css @@ -359,9 +359,14 @@ } /* COMPARISON TABLE */ - .table-wrap { overflow-x: auto; } + .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; } + .table-wrap table { + width: max-content; + min-width: 100%; + } table { - width: 100%; + width: max-content; + min-width: 100%; border-collapse: collapse; font-size: 0.85rem; } @@ -375,12 +380,17 @@ text-align: left; color: var(--muted); border-bottom: 1px solid var(--border); + white-space: nowrap; } th.hl { color: var(--accent2); } td { padding: 0.875rem 1rem; border-bottom: 1px solid var(--border); color: var(--muted); + white-space: normal; + word-break: normal; + overflow-wrap: break-word; + max-width: 300px; } td:first-child { font-weight: 500; diff --git a/template.html b/template.html index 3ce990b..5884a76 100644 --- a/template.html +++ b/template.html @@ -22,7 +22,6 @@