├── .gitignore ├── .dockerignore ├── pikvm-image ├── firstboot │ ├── 00_rw.sh │ ├── 99_ro.sh │ ├── 98_disable.sh │ ├── 10_ssh-keygen.sh │ └── 20_kvmd-gencert.sh ├── pikvm-firstboot.service ├── _pikvm-firstboot.sh └── Dockerfile.part ├── pikvm-otg-console ├── kvmd.yaml ├── ttyGS0.override └── Dockerfile.part ├── .github ├── FUNDING.yml └── workflows │ └── pi.yml ├── pikvm ├── motd ├── vcgencmd └── Dockerfile.part └── Makefile /.gitignore: -------------------------------------------------------------------------------- 1 | /.pi-builder/ 2 | /images/ 3 | /config.mk 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /.git/ 2 | /.pi-builder/ 3 | /*.img 4 | /*.img.bz2 5 | -------------------------------------------------------------------------------- /pikvm-image/firstboot/00_rw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | rw 4 | -------------------------------------------------------------------------------- /pikvm-image/firstboot/99_ro.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | ro 4 | -------------------------------------------------------------------------------- /pikvm-otg-console/kvmd.yaml: -------------------------------------------------------------------------------- 1 | otg: 2 | acm: 3 | enabled: true 4 | -------------------------------------------------------------------------------- /pikvm-image/firstboot/98_disable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | systemctl disable pikvm-firstboot 4 | -------------------------------------------------------------------------------- /pikvm-image/firstboot/10_ssh-keygen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | rm /etc/ssh/ssh_host_*key* 4 | ssh-keygen -v -A 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: pikvm 4 | custom: https://www.paypal.me/mdevaev 5 | -------------------------------------------------------------------------------- /pikvm-image/firstboot/20_kvmd-gencert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euxo pipefail 3 | rm /etc/kvmd/nginx/ssl/* 4 | kvmd-gencert --do-the-thing 5 | -------------------------------------------------------------------------------- /pikvm-otg-console/ttyGS0.override: -------------------------------------------------------------------------------- 1 | # https://github.com/raspberrypi/linux/issues/1929 2 | [Service] 3 | TTYReset=no 4 | TTYVHangup=no 5 | TTYVTDisallocate=no 6 | -------------------------------------------------------------------------------- /.github/workflows/pi.yml: -------------------------------------------------------------------------------- 1 | name: pikvm-os 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | os: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v2 11 | 12 | - name: os 13 | run: make os 14 | 15 | - name: image 16 | run: make image 17 | 18 | -------------------------------------------------------------------------------- /pikvm-image/pikvm-firstboot.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Pi-KVM - firstboot configuration 3 | After=systemd-modules-load.service 4 | Before=kvmd-otg.service kvmd-nginx.service kvmd.service sshd.service 5 | 6 | [Service] 7 | Type=oneshot 8 | ExecStart=/usr/local/bin/_pikvm-firstboot.sh --do-the-thing 9 | ExecStop=/bin/true 10 | RemainAfterExit=true 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /pikvm-otg-console/Dockerfile.part: -------------------------------------------------------------------------------- 1 | RUN systemctl enable getty@ttyGS0.service 2 | 3 | RUN echo ttyGS0 >> /etc/securetty 4 | 5 | RUN mkdir /etc/systemd/system/getty@ttyGS0.service.d 6 | COPY stages/pikvm-otg-console/ttyGS0.override /etc/systemd/system/getty@ttyGS0.service.d/override.conf 7 | 8 | COPY stages/pikvm-otg-console/kvmd.override /root/kvmd.override 9 | RUN sed -i -e 's/^{}//g' /etc/kvmd/override.yaml \ 10 | && cat /root/kvmd.override >> /etc/kvmd/override.yaml \ 11 | && rm /root/kvmd.override 12 | -------------------------------------------------------------------------------- /pikvm-image/_pikvm-firstboot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | if [ "$1" != --do-the-thing ]; then 4 | exit 1 5 | fi 6 | 7 | rw 8 | 9 | rm -f /etc/ssh/ssh_host_* 10 | ssh-keygen -v -A 11 | 12 | rm -f /etc/kvmd/nginx/ssl/* 13 | kvmd-gencert --do-the-thing 14 | 15 | if grep -q 'X-kvmd\.otgmsd' /etc/fstab; then 16 | umount /dev/mmcblk0p3 17 | parted /dev/mmcblk0 -a optimal -s resizepart 3 100% 18 | yes | mkfs.ext4 -F -m 0 /dev/mmcblk0p3 19 | mount /dev/mmcblk0p3 20 | fi 21 | 22 | systemctl disable pikvm-firstboot 23 | ro 24 | -------------------------------------------------------------------------------- /pikvm-image/Dockerfile.part: -------------------------------------------------------------------------------- 1 | RUN rm -f /etc/ssh/ssh_host_* /etc/kvmd/nginx/ssl/* 2 | 3 | COPY stages/pikvm-image/_pikvm-firstboot.sh /usr/local/bin/_pikvm-firstboot.sh 4 | COPY stages/pikvm-image/pikvm-firstboot.service /etc/systemd/system/pikvm-firstboot.service 5 | RUN systemctl enable pikvm-firstboot 6 | 7 | # https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-4#installation 8 | RUN [ "$BOARD-$ARCH" != "rpi4-aarch64" ] || ( \ 9 | sed -i 's/mmcblk0/mmcblk1/g' /etc/fstab \ 10 | && sed -i 's/mmcblk0/mmcblk1/g' /usr/local/bin/_pikvm-firstboot.sh \ 11 | ) 12 | -------------------------------------------------------------------------------- /pikvm/motd: -------------------------------------------------------------------------------- 1 | _____ _ _ ____ ____ __ 2 | | __ (_) | |/ /\ \ / / \/ | 3 | | |__) | __ | ' / \ \ / /| \ / | 4 | | ___/ | (__) | < \ \/ / | |\/| | 5 | | | | | | . \ \ / | | | | 6 | |_| |_| |_|\_\ \/ |_| |_| 7 | 8 | Welcome to Pi-KVM - Open Source IP-KVM based on Raspberry Pi 9 | ____________________________________________________________________________ 10 | 11 | The root filesystem of Pi-KVM is mounted in read-only mode by default. 12 | Use command "rw" to remount it in the RW-mode and "ro" to switch it back. 13 | 14 | To prevent kernel messages from printing to the terminal use "dmesg -n 1". 15 | 16 | To change KVM password use command "kvmd-htpasswd set admin". 17 | 18 | Useful links: 19 | * https://pikvm.org 20 | * https://wiki.archlinux.org/index.php/Network_configuration 21 | 22 | -------------------------------------------------------------------------------- /pikvm/vcgencmd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # try and keep this pure bourne shell 3 | # minimal clone of raspberry tool vcgencmd - for use with Android rpicheck and rock64 SBC 4 | 5 | command=$1 6 | case ${1} in 7 | measure_clock) 8 | case ${2} in 9 | arm) 10 | # awk is probably overkill.... 11 | value=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq | awk '{print $1 * 1000}'` 12 | echo 'frequency(45)='${value} 13 | exit 14 | ;; 15 | core) 16 | value=0 # TODO / FIXME 17 | echo 'frequency(1)='${value} 18 | exit 19 | ;; 20 | # TODO anything else thrown an error/debug 21 | esac 22 | exit 23 | ;; 24 | measure_temp) 25 | # awk is probably overkill.... 26 | value=`cat /sys/class/thermal/thermal_zone0/temp | awk '{print $1 / 1000}'` 27 | echo 'temp='${value}"'C" 28 | exit 29 | ;; 30 | measure_volts) 31 | case ${2} in 32 | core) 33 | value=1 # TODO / FIXME 34 | echo 'volt='${value}'.0000V' 35 | exit 36 | ;; 37 | # TODO anything else thrown an error/debug 38 | esac 39 | ;; 40 | get_throttled) 41 | echo 'throttled=0x00000' 42 | exit 43 | ;; 44 | version) 45 | echo 'Nov 4 2018 16:31:07' 46 | echo 'Copyright (c) 2012 rock64' 47 | echo 'version rock64_TODO (clean) (release)' 48 | exit 49 | ;; 50 | esac 51 | 52 | 53 | exit 54 | 55 | -------------------------------------------------------------------------------- /pikvm/Dockerfile.part: -------------------------------------------------------------------------------- 1 | ARG PLATFORM 2 | ARG USTREAMER_VERSION 3 | ARG KVMD_VERSION 4 | ARG KVMD_WEBTERM_VERSION 5 | ENV INSTALLATION $PLATFORM $USTREAMER_VERSION $KVMD_VERSION $KVMD_WEBTERM_VERSION 6 | RUN echo $INSTALLATION 7 | 8 | RUN pkg-install \ 9 | kvmd-platform-$PLATFORM-$BOARD \ 10 | kvmd-webterm \ 11 | netctl \ 12 | parted \ 13 | e2fsprogs 14 | 15 | RUN [ "$BOARD-$ARCH" != "rpi4-aarch64" ] || pkg-install raspberrypi-userland-aarch64 16 | 17 | COPY stages/pikvm/vcgencmd /tmp/ 18 | RUN [ -f /opt/vc/bin/vcgencmd ] || ( mkdir -p /opt/vc/bin && cp -a /tmp/vcgencmd /opt/vc/bin/vcgencmd ) 19 | 20 | RUN systemctl enable kvmd \ 21 | && systemctl enable kvmd-nginx \ 22 | && systemctl enable kvmd-webterm \ 23 | && ([[ ! $PLATFORM =~ ^.*-hdmi$ ]] || systemctl enable kvmd-tc358743) \ 24 | && ([[ ! $PLATFORM =~ ^v[01]-.*$ ]] || systemctl mask serial-getty@ttyAMA0.service) \ 25 | && ([[ ! $PLATFORM =~ ^v2-.*$ ]] || ( \ 26 | systemctl enable kvmd-otg \ 27 | && echo "/dev/mmcblk0p3 /var/lib/kvmd/msd ext4 nodev,nosuid,noexec,ro,errors=remount-ro,data=journal,X-kvmd.otgmsd-root=/var/lib/kvmd/msd,X-kvmd.otgmsd-user=kvmd 0 0" >> /etc/fstab \ 28 | )) 29 | 30 | COPY stages/pikvm/motd /etc/ 31 | 32 | RUN [ ! -f /boot/cmdline.txt ] || sed -i -f /usr/share/kvmd/configs.default/os/cmdline/$PLATFORM-$BOARD.sed /boot/cmdline.txt \ 33 | && [ ! -f /usr/share/kvmd/configs.default/os/boot-config/$PLATFORM-$BOARD.txt ] \ 34 | || cp /usr/share/kvmd/configs.default/os/boot-config/$PLATFORM-$BOARD.txt /boot/config.txt 35 | 36 | RUN sed -i -e "s/-session optional pam_systemd.so/#-session optional pam_systemd.so/g" /etc/pam.d/system-login 37 | 38 | ARG WIFI_ESSID 39 | ARG WIFI_PASSWD 40 | ARG WIFI_IFACE 41 | RUN [ -z "$WIFI_ESSID" ] || ( \ 42 | export config="/etc/netctl/$WIFI_IFACE-${WIFI_ESSID/ /_}" \ 43 | && echo "Description='Generated by Pi-KVM OS build system'" > $config \ 44 | && echo "Interface='$WIFI_IFACE'" >> $config \ 45 | && echo "Connection=wireless" >> $config \ 46 | && echo "Security=wpa" >> $config \ 47 | && echo "ESSID='$WIFI_ESSID'" >> $config \ 48 | && echo "IP=dhcp" >> $config \ 49 | && echo "Key='$WIFI_PASSWD'" >> $config \ 50 | && systemctl enable netctl-auto@$WIFI_IFACE.service \ 51 | ) 52 | 53 | ARG ROOT_PASSWD 54 | ENV ROOT_PASSWD $ROOT_PASSWD 55 | RUN echo "root:$ROOT_PASSWD" | chpasswd \ 56 | && echo "PermitRootLogin yes" >> /etc/ssh/sshd_config \ 57 | && userdel -r -f alarm 58 | 59 | ARG WEBUI_ADMIN_PASSWD 60 | ENV WEBUI_ADMIN_PASSWD $WEBUI_ADMIN_PASSWD 61 | RUN echo "$WEBUI_ADMIN_PASSWD" | kvmd-htpasswd set --read-stdin admin 62 | 63 | ARG IPMI_ADMIN_PASSWD 64 | ENV IPMI_ADMIN_PASSWD $IPMI_ADMIN_PASSWD 65 | RUN sed -i "\$d" /etc/kvmd/ipmipasswd \ 66 | && echo "admin:$IPMI_ADMIN_PASSWD -> admin:$WEBUI_ADMIN_PASSWD" >> /etc/kvmd/ipmipasswd 67 | 68 | ARG NEW_HTTPS_CERT 69 | ENV NEW_HTTPS_CERT $NEW_HTTPS_CERT 70 | RUN echo $NEW_HTTPS_CERT \ 71 | && kvmd-gencert --do-the-thing 72 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | -include config.mk 2 | 3 | BOARD ?= rpi4 4 | ARCH ?= arm 5 | PLATFORM ?= v2-hdmi 6 | UBOOT ?= 7 | STAGES ?= __init__ os pikvm-repo watchdog ro no-audit pikvm pikvm-image __cleanup__ 8 | 9 | HOSTNAME ?= pikvm 10 | LOCALE ?= en_US 11 | TIMEZONE ?= Europe/Moscow 12 | #REPO_URL ?= http://mirror.yandex.ru/archlinux-arm 13 | REPO_URL ?= http://de3.mirror.archlinuxarm.org 14 | BUILD_OPTS ?= 15 | BUILDER_URL ?= https://github.com/mdevaev/pi-builder 16 | PIKVM_REPO_URL ?= https://pikvm.org/repos 17 | PIKVM_REPO_KEY ?= 912C773ABBD1B584 18 | 19 | WIFI_ESSID ?= 20 | WIFI_PASSWD ?= 21 | WIFI_IFACE ?= wlan0 22 | 23 | ROOT_PASSWD ?= root 24 | WEBUI_ADMIN_PASSWD ?= admin 25 | IPMI_ADMIN_PASSWD ?= admin 26 | 27 | CARD ?= /dev/mmcblk0 28 | IMAGE_FILE ?= images/$(PLATFORM)-$(BOARD)-$(ARCH)$(if $(UBOOT),-$(UBOOT),).img 29 | 30 | 31 | # ===== 32 | SHELL = /usr/bin/env bash 33 | _BUILDER_DIR = ./.pi-builder 34 | 35 | define fetch_version 36 | $(shell curl --silent "$(PIKVM_REPO_URL)/$(BOARD)-$(ARCH)/latest/$(1)") 37 | endef 38 | 39 | 40 | # ===== 41 | all: 42 | @ echo "Available commands:" 43 | @ echo " make # Print this help" 44 | @ echo " make os # Build OS with your default config" 45 | @ echo " make shell # Run Arch-ARM shell" 46 | @ echo " make install # Install rootfs to partitions on $(CARD)" 47 | @ echo " make image # Create a binary image for burning outside of make install" 48 | @ echo " make scan # Find all RPi devices in the local network" 49 | @ echo " make clean # Remove the generated rootfs" 50 | @ echo " make clean-all # Remove the generated rootfs and pi-builder toolchain" 51 | 52 | 53 | shell: $(_BUILDER_DIR) 54 | make -C $(_BUILDER_DIR) shell 55 | 56 | 57 | os: $(_BUILDER_DIR) 58 | rm -rf $(_BUILDER_DIR)/stages/{pikvm,pikvm-image,pikvm-otg-console} 59 | cp -a pikvm pikvm-image pikvm-otg-console $(_BUILDER_DIR)/stages 60 | make -C $(_BUILDER_DIR) os \ 61 | NC=$(NC) \ 62 | BUILD_OPTS=" $(BUILD_OPTS) \ 63 | --build-arg PLATFORM=$(PLATFORM) \ 64 | --build-arg USTREAMER_VERSION=$(call fetch_version,ustreamer) \ 65 | --build-arg KVMD_VERSION=$(call fetch_version,kvmd) \ 66 | --build-arg KVMD_WEBTERM_VERSION=$(call fetch_version,kvmd-webterm) \ 67 | --build-arg WIFI_ESSID='$(WIFI_ESSID)' \ 68 | --build-arg WIFI_PASSWD='$(WIFI_PASSWD)' \ 69 | --build-arg WIFI_IFACE='$(WIFI_IFACE)' \ 70 | --build-arg ROOT_PASSWD='$(ROOT_PASSWD)' \ 71 | --build-arg WEBUI_ADMIN_PASSWD='$(WEBUI_ADMIN_PASSWD)' \ 72 | --build-arg IPMI_ADMIN_PASSWD='$(IPMI_ADMIN_PASSWD)' \ 73 | --build-arg NEW_HTTPS_CERT=$(shell uuidgen) \ 74 | " \ 75 | PROJECT=pikvm-os-$(PLATFORM) \ 76 | BOARD=$(BOARD) \ 77 | ARCH=$(ARCH) \ 78 | UBOOT=$(UBOOT) \ 79 | STAGES='$(STAGES)' \ 80 | HOSTNAME=$(HOSTNAME) \ 81 | LOCALE=$(LOCALE) \ 82 | TIMEZONE=$(TIMEZONE) \ 83 | REPO_URL=$(REPO_URL) \ 84 | PIKVM_REPO_URL=$(PIKVM_REPO_URL) \ 85 | PIKVM_REPO_KEY=$(PIKVM_REPO_KEY) 86 | 87 | 88 | $(_BUILDER_DIR): 89 | git clone --depth=1 $(BUILDER_URL) $(_BUILDER_DIR) 90 | 91 | 92 | update: $(_BUILDER_DIR) 93 | cd $(_BUILDER_DIR) && git pull --rebase 94 | git pull --rebase 95 | 96 | 97 | install: $(_BUILDER_DIR) 98 | make -C $(_BUILDER_DIR) install \ 99 | CARD=$(CARD) \ 100 | BOARD=$(BOARD) \ 101 | ARCH=$(ARCH) \ 102 | UBOOT=$(UBOOT) \ 103 | CARD_DATA_FS_TYPE=$(if $(findstring v2-hdmi,$(PLATFORM)),ext4,) \ 104 | CARD_DATA_FS_FLAGS=-m0 105 | 106 | 107 | scan: $(_BUILDER_DIR) 108 | make -C $(_BUILDER_DIR) scan 109 | 110 | 111 | clean: $(_BUILDER_DIR) 112 | make -C $(_BUILDER_DIR) clean 113 | 114 | 115 | clean-all: 116 | - make -C $(_BUILDER_DIR) clean-all 117 | rm -rf $(_BUILDER_DIR) 118 | 119 | 120 | image: 121 | mkdir -p images 122 | sudo bash -x -c ' \ 123 | dd if=/dev/zero of=$(IMAGE_FILE) bs=512 count=12582912 \ 124 | && device=`losetup --find --show $(IMAGE_FILE)` \ 125 | && make install CARD=$$device BOARD=$(BOARD) ARCH=$(ARCH) UBOOT=$(UBOOT)\ 126 | && losetup -d $$device \ 127 | ' 128 | bzip2 -f $(IMAGE_FILE) 129 | sha1sum $(IMAGE_FILE).bz2 | awk '{print $$1}' > $(IMAGE_FILE).bz2.sha1 130 | 131 | 132 | upload: 133 | rsync -rl --progress --delete images root@pikvm.org:/var/www/images2 134 | ssh root@pikvm.org "bash -c 'mv /var/www/images2/* /var/www/images/; rmdir /var/www/images2'" 135 | --------------------------------------------------------------------------------