diff --git a/README.md b/README.md new file mode 100644 index 0000000..7209429 --- /dev/null +++ b/README.md @@ -0,0 +1,435 @@ +# mentalnet-microcontainers + +A DIY provisioning cloud for your homelab. + +`mentalnet-microcontainers` gives you a tiny, self-hosted control plane for spinning up Docker containers and using them like lightweight VMs: + +- Web UI to paste an SSH public key and pick a base image +- Automatically provisions a container with: + - User `micro` (with `sudo`) + - SSH key–only authentication + - Unique SSH port on the host + - Dedicated 3 GB ext4 filesystem mounted as `/home/micro` +- Designed for “I just want a throwaway dev box on my own hardware”, not full multi-tenant hosting + +--- + +## What this actually does + +When you hit the web UI and create a “microcontainer”, the app: + +1. Validates your SSH public key. +2. Generates a unique container name: + - e.g. `mc-debian-myproject-8c5268` +3. Creates a tenant directory on the host: + - `/srv/microcontainers//` +4. Creates a sparse 3 GB `disk.img`: + - `fallocate -l 3G disk.img` + - `mkfs.ext4 disk.img` +5. Mounts it on the host: + - `/mnt/microcontainers//` +6. Writes your SSH key to: + - `/mnt/microcontainers//.ssh/authorized_keys` +7. Fixes ownership to match the in-container user: + - `chown -R 1000:1000 /mnt/microcontainers/` +8. Picks a free port in a range (e.g. `20000–21000`). +9. Starts a Docker container: + + ```bash + docker run -d \ + --name \ + --memory=512m \ + --memory-swap=512m \ + -p HOST_PORT:22 \ + -v /mnt/microcontainers/:/home/micro \ + micro-debian-dev:latest # or micro-fedora43-dev:latest +```` + +10. Shows you an SSH command like: + + ```bash + ssh micro@your-hostname -p 20013 + ``` + +From your perspective, it feels like “click → get a tiny VM with a 3 GB home and sudo.” + +--- + +## Features + +* **DIY provisioning cloud** + Turn one Docker host into a small pool of micro-VM-like environments. + +* **Web UI (Flask)** + + * Paste SSH key + * Choose base image (Debian / Fedora) + * Optional label to tag the container name + +* **Per-tenant filesystem** + + * Each microcontainer gets its own 3 GB ext4 filesystem + * Mounted as `/home/micro` + * Prevents a single tenant from filling the host via `$HOME` + +* **SSH-only login** + + * User: `micro` + * Auth: SSH public key only (no passwords) + * `sudo` enabled inside the container + +* **Port range allocation** + + * Host ports auto-assigned from a configured range (e.g. `20000–21000`) + * One container per SSH port + +* **Image-agnostic** + + * Comes with sample Debian & Fedora dev images + * Easy to add your own `micro-*-dev` images + +--- + +## Repository layout + +Example layout: + +```text +mentalnet-microcontainers/ + app.py + requirements.txt + docker/ + micro-debian-dev/ + Dockerfile + build-dockerfile.sh + micro-fedora43-dev/ + Dockerfile + build-dockerfile.sh + README.md +``` + +You can add more images under `docker/` later (e.g. `micro-alpine-dev`, `micro-arch-dev`, etc.). + +--- + +## Base images + +### Build script convention + +Each image directory contains a simple build script: + +`docker/micro-debian-dev/build-dockerfile.sh` (same pattern for Fedora): + +```bash +#!/usr/bin/env bash +set -euo pipefail + +IMAGE_NAME="$(basename "$(pwd)")" + +echo "Building Docker image: ${IMAGE_NAME}:latest" +docker build -t "${IMAGE_NAME}:latest" . +``` + +Name your directory the same as the image you want (`micro-debian-dev`, `micro-fedora43-dev`, etc.) and the script will build `IMAGE_NAME:latest` automatically. + +--- + +### Debian dev box (`micro-debian-dev`) + +`docker/micro-debian-dev/Dockerfile`: + +```dockerfile +FROM debian:stable-slim + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + openssh-server \ + sudo \ + ca-certificates \ + git \ + curl wget \ + vim nano \ + htop \ + build-essential && \ + rm -rf /var/lib/apt/lists/* + +# Create 'micro' user with fixed uid/gid 1000 +RUN useradd -m -u 1000 -U -s /bin/bash micro && \ + echo "micro:ChangeMe123" | chpasswd && \ + usermod -aG sudo micro + +# Prepare .ssh directory (runtime volume will mount over /home/micro) +RUN mkdir -p /home/micro/.ssh && \ + chown -R micro:micro /home/micro && \ + chmod 700 /home/micro/.ssh + +# SSH server config: key-only login, use ~/.ssh/authorized_keys +RUN sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config || true && \ + sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config || true && \ + sed -i 's/^#KbdInteractiveAuthentication yes/KbdInteractiveAuthentication no/' /etc/ssh/sshd_config || true && \ + sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config || true && \ + sed -i 's|^#AuthorizedKeysFile.*|AuthorizedKeysFile .ssh/authorized_keys|' /etc/ssh/sshd_config || true && \ + echo 'UsePAM no' >> /etc/ssh/sshd_config + +RUN mkdir -p /var/run/sshd && \ + ssh-keygen -A + +EXPOSE 22 + +CMD ["/usr/sbin/sshd", "-D"] +``` + +Build: + +```bash +cd docker/micro-debian-dev +./build-dockerfile.sh +``` + +--- + +### Fedora 43 dev box (`micro-fedora43-dev`) + +`docker/micro-fedora43-dev/Dockerfile`: + +```dockerfile +FROM fedora:43 + +RUN dnf -y update && \ + dnf -y install \ + openssh-server \ + sudo \ + ca-certificates \ + git \ + curl wget \ + vim nano \ + htop \ + gcc gcc-c++ make && \ + dnf clean all && \ + rm -rf /var/cache/dnf + +RUN useradd -m -u 1000 -U -s /bin/bash micro && \ + echo "micro:ChangeMe123" | chpasswd && \ + usermod -aG wheel micro + +RUN mkdir -p /home/micro/.ssh && \ + chown -R micro:micro /home/micro && \ + chmod 700 /home/micro/.ssh + +RUN sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config || true && \ + sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config || true && \ + sed -i 's/^#KbdInteractiveAuthentication yes/KbdInteractiveAuthentication no/' /etc/ssh/sshd_config || true && \ + sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config || true && \ + sed -i 's|^#AuthorizedKeysFile.*|AuthorizedKeysFile .ssh/authorized_keys|' /etc/ssh/sshd_config || true && \ + echo 'UsePAM no' >> /etc/ssh/sshd_config + +RUN mkdir -p /var/run/sshd && \ + ssh-keygen -A + +EXPOSE 22 + +CMD ["/usr/sbin/sshd", "-D"] +``` + +Build: + +```bash +cd docker/micro-fedora43-dev +./build-dockerfile.sh +``` + +--- + +## The Flask app (`app.py`) + +Core ideas in `app.py`: + +* Configuration: + + ```python + IMAGES = { + "debian": { + "docker_image": "micro-debian-dev:latest", + "label": "Debian Dev Box (micro-debian-dev)" + }, + "fedora": { + "docker_image": "micro-fedora43-dev:latest", + "label": "Fedora 43 Dev Box (micro-fedora43-dev)" + }, + } + + DEFAULT_IMAGE_KEY = "debian" + + DATA_ROOT = "/srv/microcontainers" # per-tenant metadata + disk.img + MOUNT_ROOT = "/mnt/microcontainers" # where disk.img files are mounted + HOSTNAME = "arthur.lan" # only used for display in UI + PORT_RANGE_START = 20000 + PORT_RANGE_END = 21000 + ``` + +* Each POST to `/`: + + * Validates the SSH key + * Picks an image + * Generates a container name + * Calls `ensure_tenant_disk()` to create/mount the 3 GB ext4 filesystem and write `authorized_keys` + * Chooses a free port in the range + * Calls `run_docker_container()` with: + + * `-p HOST_PORT:22` + * `-v home_mount:/home/micro` + +Returned info includes container name, host port, and an SSH command. + +--- + +## Running the app + +### 1. Install dependencies + +Create a venv (optional but recommended): + +```bash +python3 -m venv venv +source venv/bin/activate +pip install -r requirements.txt +``` + +`requirements.txt`: + +```text +Flask>=3.0,<4.0 +``` + +### 2. Run the Flask server + +```bash +python app.py +``` + +By default it listens on `0.0.0.0:5000`. + +You may also want a firewall rule to allow your LAN: + +```bash +# Example with iptables (adjust to your LAN subnet) +iptables -A INPUT -s 192.168.86.0/24 -p tcp --dport 5000 -m state --state NEW -j ACCEPT +``` + +### 3. Use the UI + +From a machine on your LAN: + +1. Open `http://HOST:5000/` (replace `HOST` with your VM’s IP/hostname). +2. Paste your SSH public key (one line, e.g. `ssh-ed25519 AAAA... user@host`). +3. Choose an image (`debian` or `fedora`). +4. Optionally add a label (e.g. `project-x-dev`). +5. Click **Provision MicroContainer**. + +If successful you’ll see something like: + +```text +Container created! +Image: debian — Debian Dev Box (micro-debian-dev) +Container name: mc-debian-project-x-8c5268 +Host port: 20013 +SSH command: +ssh micro@arthur.lan -p 20013 +``` + +--- + +## Configuration + +You can tune basic behavior at the top of `app.py`: + +```python +DATA_ROOT = "/srv/microcontainers" +MOUNT_ROOT = "/mnt/microcontainers" +HOSTNAME = "arthur.lan" # used only for the SSH hint in the UI +PORT_RANGE_START = 20000 +PORT_RANGE_END = 21000 +``` + +Examples: + +* On a VPS, you might set: + + ```python + HOSTNAME = "your.vps.domain" + ``` + +* To change ports to e.g. `30000–30100`: + + ```python + PORT_RANGE_START = 30000 + PORT_RANGE_END = 30100 + ``` + +--- + +## Security notes + +This is a **homelab prototype**, not hardened multi-tenant hosting. + +Things to be aware of: + +* **No auth on the UI** + Anyone who can reach port 5000 can create containers. + Recommended: + + * Bind to `127.0.0.1` and reverse tunnel + * Or put it behind a VPN / reverse proxy with auth + +* **Runs as root** + The app calls `fallocate`, `mkfs.ext4`, `mount`, `chown`, and `docker run`. + It’s intended to run as root (or equivalent) on a box you control. + +* **SSH ports exposed on the host** + Example: `20000–21000`. + Use your firewall / router to decide who can reach them. + +* **No automatic cleanup yet** + Stopping/removing containers and unmounting disks is manual for now: + + * `docker ps`, `docker stop`, `docker rm` + * `umount /mnt/microcontainers/` + * Optionally `rm -rf /srv/microcontainers//` + +Use this like a DIY “micro-VPS factory” in your lab, not a fully managed public cloud. + +--- + +### Secret key + +Flask uses `app.secret_key` to sign session data and flash messages. + +In `app.py` this is read from the `MICROCONTAINERS_SECRET_KEY` environment variable: + +```python +app.secret_key = os.environ.get("MICROCONTAINERS_SECRET_KEY", "dev-only-not-secret") +```` + +For anything beyond local testing, set a real random secret: + +```bash +export MICROCONTAINERS_SECRET_KEY="$(python3 -c 'import secrets; print(secrets.token_hex(32))')" +``` + +--- + +## Ideas / future work + +* Add a simple **cleanup UI** for stopping/removing containers and unmounting disks. +* Optional **basic auth** or token-protected UI. +* More **SKUs**: + + * `micro-alpine-dev`, `micro-arch-dev`, `micro-nix-dev`, etc. +* Stats page showing: + + * Used vs total space per tenant + * Running containers and their ports + + diff --git a/app.py b/app.py index 90fbc2e..c8ba557 100644 --- a/app.py +++ b/app.py @@ -7,17 +7,31 @@ import uuid from flask import Flask, request, render_template_string, flash app = Flask(__name__) -app.secret_key = "change-me-in-production" +app.secret_key = os.environ.get("MICROCONTAINERS_SECRET_KEY", "dev-only-not-secret") # --- Config ----------------------------------------------------------------- -DOCKER_IMAGE = "micro-debian-dev:latest" # built from the Dockerfile above -DATA_ROOT = "/srv/microcontainers" # where per-tenant dirs live +IMAGES = { + "debian": { + "docker_image": "micro-debian-dev:latest", + "label": "Debian Dev Box (micro-debian-dev)" + }, + "fedora": { + "docker_image": "micro-fedora43-dev:latest", + "label": "Fedora 43 Dev Box (micro-fedora43-dev)" + }, +} + +DEFAULT_IMAGE_KEY = "debian" + +DATA_ROOT = "/srv/microcontainers" # per-tenant metadata + disk.img +MOUNT_ROOT = "/mnt/microcontainers" # where disk.img files are mounted HOSTNAME = "arthur.lan" # or "mentalnet.xyz" if you prefer PORT_RANGE_START = 20000 PORT_RANGE_END = 21000 os.makedirs(DATA_ROOT, exist_ok=True) +os.makedirs(MOUNT_ROOT, exist_ok=True) # --- Helpers ---------------------------------------------------------------- @@ -49,21 +63,75 @@ def validate_ssh_key(key: str) -> bool: return any(key.startswith(p) for p in allowed_prefixes) -def run_docker_container(container_name: str, ssh_dir: str, host_port: int): +def is_mounted(mount_point: str) -> bool: + """Check if a given mount point is already mounted.""" + try: + with open("/proc/mounts", "r") as f: + for line in f: + parts = line.split() + if len(parts) >= 2 and parts[1] == mount_point: + return True + except FileNotFoundError: + pass + return False + + +def ensure_tenant_disk(container_name: str, ssh_key: str, size_gb: int = 3) -> str: + """ + Ensure a per-tenant disk.img exists, is formatted, mounted, and has + .ssh/authorized_keys populated. + + Returns the host mount point path, which will be bind-mounted to /home/micro. + """ + tenant_root = os.path.join(DATA_ROOT, container_name) + os.makedirs(tenant_root, exist_ok=True) + + disk_img = os.path.join(tenant_root, "disk.img") + mount_point = os.path.join(MOUNT_ROOT, container_name) + os.makedirs(mount_point, exist_ok=True) + + # 1) Create sparse disk.img if it doesn't exist + if not os.path.exists(disk_img): + subprocess.run(["fallocate", "-l", f"{size_gb}G", disk_img], check=True) + subprocess.run(["mkfs.ext4", "-F", disk_img], check=True) + + # 2) Mount it if not already mounted + if not is_mounted(mount_point): + subprocess.run(["mount", "-o", "loop", disk_img, mount_point], check=True) + + # 3) Prepare /home/micro layout inside the filesystem + # (we're mounting this whole thing as /home/micro in the container) + ssh_dir = os.path.join(mount_point, ".ssh") + os.makedirs(ssh_dir, exist_ok=True) + + auth_keys_path = os.path.join(ssh_dir, "authorized_keys") + with open(auth_keys_path, "w") as f: + f.write(ssh_key.strip() + "\n") + + # Proper perms for SSH + os.chmod(ssh_dir, 0o700) + os.chmod(auth_keys_path, 0o600) + + # Make everything in /home/micro look like micro:micro (uid/gid 1000) + subprocess.run(["chown", "-R", "1000:1000", mount_point], check=True) + + return mount_point + + +def run_docker_container(container_name: str, host_port: int, docker_image: str, home_mount: str): """ Start the tenant container: - Binds host_port -> container:22 - - Mounts authorized_keys -> /home/micro/.ssh/authorized_keys (read-only) + - Mounts per-tenant 3GB disk as /home/micro """ - auth_keys_path = os.path.join(ssh_dir, "authorized_keys") cmd = [ "docker", "run", "-d", "--name", container_name, "--memory=512m", "--memory-swap=512m", "-p", f"{host_port}:22", - "-v", f"{auth_keys_path}:/home/micro/.ssh/authorized_keys:ro", - DOCKER_IMAGE, + "-v", f"{home_mount}:/home/micro", + docker_image, ] subprocess.run(cmd, check=True) @@ -94,7 +162,7 @@ INDEX_TEMPLATE = """ border: 1px solid #333; } label { display: block; margin-bottom: 8px; font-weight: 600; } - textarea, input[type=text] { + textarea, input[type=text], select { width: 100%; box-sizing: border-box; background: #101010; @@ -127,8 +195,14 @@ INDEX_TEMPLATE = """

This prototype spins up a small Docker-based "micro VM" and wires in your SSH public key.

    -
  • Base image: {{ docker_image }}
  • +
  • Available base images:
  • +
      + {% for key, info in images.items() %} +
    • {{ key }}: {{ info.label }}
    • + {% endfor %} +
  • User: micro
  • +
  • Per-tenant /home size: 3 GB (loopback ext4)
  • SSH inside container: port 22
  • Host port: auto-assigned from {{ port_start }}-{{ port_end }}
@@ -147,6 +221,7 @@ INDEX_TEMPLATE = """ {% if result %}

Container created!

+

Image: {{ result.image_key }} — {{ images[result.image_key].label }}

Container name: {{ result.name }}

Host port: {{ result.port }}

SSH command:

@@ -158,6 +233,15 @@ INDEX_TEMPLATE = """
+ + + @@ -180,87 +264,96 @@ def index(): if request.method == "GET": return render_template_string( INDEX_TEMPLATE, - docker_image=DOCKER_IMAGE, + images=IMAGES, port_start=PORT_RANGE_START, port_end=PORT_RANGE_END, result=None, ssh_key="", hostname=HOSTNAME, + selected_image=DEFAULT_IMAGE_KEY, ) # POST: handle provisioning ssh_key = (request.form.get("ssh_key") or "").strip() note = (request.form.get("note") or "").strip() + image_key = (request.form.get("image") or DEFAULT_IMAGE_KEY).strip() + + if image_key not in IMAGES: + image_key = DEFAULT_IMAGE_KEY + + docker_image = IMAGES[image_key]["docker_image"] if not validate_ssh_key(ssh_key): flash("Invalid SSH public key format. Please paste a standard OpenSSH public key line.") return render_template_string( INDEX_TEMPLATE, - docker_image=DOCKER_IMAGE, + images=IMAGES, port_start=PORT_RANGE_START, port_end=PORT_RANGE_END, result=None, ssh_key=ssh_key, hostname=HOSTNAME, + selected_image=image_key, ) # Generate a container name suffix = uuid.uuid4().hex[:6] - base_name = "mc" + base_name = f"mc-{image_key}" if note: safe_note = "".join(c for c in note.lower().replace(" ", "-") if c.isalnum() or c in "-_") - base_name = f"mc-{safe_note}" + base_name = f"mc-{image_key}-{safe_note}" container_name = f"{base_name}-{suffix}" - # Tenant SSH dir on host - tenant_root = os.path.join(DATA_ROOT, container_name) - tenant_ssh_dir = os.path.join(tenant_root, "ssh") - os.makedirs(tenant_ssh_dir, exist_ok=True) - - # Write authorized_keys - auth_keys_path = os.path.join(tenant_ssh_dir, "authorized_keys") - with open(auth_keys_path, "w") as f: - f.write(ssh_key.strip() + "\n") - - # Make it look like micro:micro (uid/gid 1000) to sshd in the container - os.chmod(auth_keys_path, 0o600) + # Ensure per-tenant disk (3 GB ext4) and authorized_keys try: - os.chown(auth_keys_path, 1000, 1000) # micro:micro inside container - except PermissionError: - # If Flask isn't running as root, this will fail; on your VM it should succeed. - pass - - # Choose a free port and start container - host_port = find_free_port() - try: - run_docker_container(container_name, tenant_ssh_dir, host_port) + home_mount = ensure_tenant_disk(container_name, ssh_key, size_gb=3) except subprocess.CalledProcessError as e: - flash(f"Error starting container: {e}") + flash(f"Error preparing tenant disk: {e}") return render_template_string( INDEX_TEMPLATE, - docker_image=DOCKER_IMAGE, + images=IMAGES, port_start=PORT_RANGE_START, port_end=PORT_RANGE_END, result=None, ssh_key=ssh_key, hostname=HOSTNAME, + selected_image=image_key, + ) + + # Choose a free port and start container + host_port = find_free_port() + try: + run_docker_container(container_name, host_port, docker_image, home_mount) + except subprocess.CalledProcessError as e: + flash(f"Error starting container: {e}") + return render_template_string( + INDEX_TEMPLATE, + images=IMAGES, + port_start=PORT_RANGE_START, + port_end=PORT_RANGE_END, + result=None, + ssh_key=ssh_key, + hostname=HOSTNAME, + selected_image=image_key, ) class Result: - def __init__(self, name, port): + def __init__(self, name, port, image_key): self.name = name self.port = port + self.image_key = image_key - result = Result(container_name, host_port) + result = Result(container_name, host_port, image_key) return render_template_string( INDEX_TEMPLATE, - docker_image=DOCKER_IMAGE, + images=IMAGES, port_start=PORT_RANGE_START, port_end=PORT_RANGE_END, result=result, ssh_key="", hostname=HOSTNAME, + selected_image=image_key, ) diff --git a/micro-debian-dev/Dockerfile b/micro-debian-dev/Dockerfile index 18a01eb..a6dd7ec 100644 --- a/micro-debian-dev/Dockerfile +++ b/micro-debian-dev/Dockerfile @@ -40,7 +40,7 @@ RUN mkdir -p /var/run/sshd && \ # Fastfetch config for micro (optional flair) RUN mkdir -p /home/micro/.config/fastfetch -COPY fastfetch_config.json /home/micro/.config/fastfetch/config.json +COPY fastfetch_config.json /home/micro/.config/fastfetch/config.jsonc RUN chown -R micro:micro /home/micro/.config && \ echo 'if command -v fastfetch >/dev/null 2>&1; then fastfetch; fi' >> /home/micro/.bashrc && \ chown micro:micro /home/micro/.bashrc diff --git a/micro-debian-dev/build-dockerfile.sh b/micro-debian-dev/build-dockerfile.sh index cce4c78..f3a702f 100755 --- a/micro-debian-dev/build-dockerfile.sh +++ b/micro-debian-dev/build-dockerfile.sh @@ -1,3 +1,8 @@ -#!/bin/bash -#echo $(basename $(pwd)) -docker build -t $(basename $(pwd)):latest . +#!/usr/bin/env bash +set -euo pipefail + +IMAGE_NAME="$(basename "$(pwd)")" + +echo "Building Docker image: ${IMAGE_NAME}:latest" +docker build -t "${IMAGE_NAME}:latest" . + diff --git a/micro-fedora43-dev/Dockerfile b/micro-fedora43-dev/Dockerfile new file mode 100644 index 0000000..89bdf4f --- /dev/null +++ b/micro-fedora43-dev/Dockerfile @@ -0,0 +1,51 @@ +FROM fedora:43 + +# Basic tools + SSH + dev stack (+ fastfetch if available) +RUN dnf -y update && \ + dnf -y install \ + openssh-server \ + sudo \ + ca-certificates \ + git \ + curl wget \ + vim nano \ + htop \ + gcc gcc-c++ make \ + fastfetch || true && \ + dnf clean all && \ + rm -rf /var/cache/dnf + +# Create 'micro' user with fixed uid/gid 1000 +RUN useradd -m -u 1000 -U -s /bin/bash micro && \ + echo "micro:ChangeMe123" | chpasswd && \ + usermod -aG wheel micro + +# Prepare .ssh directory +RUN mkdir -p /home/micro/.ssh && \ + chown -R micro:micro /home/micro && \ + chmod 700 /home/micro/.ssh + +# SSH server config: key-only login, use ~/.ssh/authorized_keys +RUN sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config || true && \ + sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config || true && \ + sed -i 's/^#KbdInteractiveAuthentication yes/KbdInteractiveAuthentication no/' /etc/ssh/sshd_config || true && \ + sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config || true && \ + sed -i 's|^#AuthorizedKeysFile.*|AuthorizedKeysFile .ssh/authorized_keys|' /etc/ssh/sshd_config || true && \ + echo 'UsePAM no' >> /etc/ssh/sshd_config + +# Generate host keys and make sure run dir exists +RUN mkdir -p /var/run/sshd && \ + ssh-keygen -A + +# Fastfetch config for micro (reuse your existing JSON) +RUN mkdir -p /home/micro/.config/fastfetch +COPY fastfetch_config.json /home/micro/.config/fastfetch/config.jsonc +RUN chown -R micro:micro /home/micro/.config && \ + echo 'if command -v fastfetch >/dev/null 2>&1; then fastfetch; fi' >> /home/micro/.bashrc && \ + echo 'alias fastfetch="fastfetch --config $HOME/.config/fastfetch/config.jsonc"' >> /home/micro/.bashrc && \ + chown micro:micro /home/micro/.bashrc + +EXPOSE 22 + +CMD ["/usr/sbin/sshd", "-D"] + diff --git a/micro-fedora43-dev/build-dockerfile.sh b/micro-fedora43-dev/build-dockerfile.sh new file mode 100755 index 0000000..f3a702f --- /dev/null +++ b/micro-fedora43-dev/build-dockerfile.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail + +IMAGE_NAME="$(basename "$(pwd)")" + +echo "Building Docker image: ${IMAGE_NAME}:latest" +docker build -t "${IMAGE_NAME}:latest" . + diff --git a/micro-fedora43-dev/fastfetch_config.json b/micro-fedora43-dev/fastfetch_config.json new file mode 100644 index 0000000..cd6abaa --- /dev/null +++ b/micro-fedora43-dev/fastfetch_config.json @@ -0,0 +1,15 @@ +{ + "display": { + "separator": " == " + }, + "modules": [ + "title", + "os", + "kernel", + "cpu", + "memory", + "disk", + "shell" + ] +} + diff --git a/start-server.sh b/start-server.sh new file mode 100755 index 0000000..303f43a --- /dev/null +++ b/start-server.sh @@ -0,0 +1,4 @@ +#!/bin/bash +export MICROCONTAINERS_SECRET_KEY="$(python3 -c 'import secrets; print(secrets.token_hex(32))')" +python3 app.py +