{"id":408191,"date":"2024-06-29T20:00:31","date_gmt":"2024-06-29T20:00:31","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=408191"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=408191","title":{"rendered":"<span>Boot Ubuntu via http\/ftp server with pxe(diskless boot)<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2 id=\"intro\">Intro<\/h2>\n<p>  <\/p>\n<p>PXE is a great solution for booting a diskless computer (or a computer without an OS installed). This method is often used for terminal stations and OS mass installation.<\/p>\n<p>  <\/p>\n<p>Stock ubuntu (16.04) in pxe-mode can mount rootfs only from NFS. But this is not a great idea: any difficulties with the network\/NFS server and the user gets problems.<\/p>\n<p>  <\/p>\n<p>In my opinion, it&#8217;s best to use other protocols, such as http\/ftp. Once booting, you will have an independent system <\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p>You should add information about the limits of applicability of the proposed solution and what are the dependencies and restrictions.<\/p>\n<p>  <\/p>\n<h2 id=\"pxe-short-info\">Pxe short info<\/h2>\n<p>  <\/p>\n<p>PXE (Preboot Execution Environment) is a special method for booting a computer from the bios \/ EFI.<br \/>  How it works (simplified scheme):<\/p>\n<p>  <\/p>\n<ul>\n<li>The computer bios\/uefi sends ordinary dhcp request (DHCPDISCOVER) <\/li>\n<li>The dhcp server sends a response with the next-server option <\/li>\n<li>The computer sends DHCPREQUEST\/DHCPINFORM request <\/li>\n<li>The dhcp server sends TFTP server address and the filename to upload <\/li>\n<li>The computer downloads this file from the tftp server. Its size is limited so, often, it&#8217;s a bootloader like pxeinux <\/li>\n<li>pxelinux reads its own config and downloads Linux kernel using initramfs <\/li>\n<li>Linux kernel downloads squashfs with main rootfs <\/li>\n<li>switch_root to its squashfs<\/li>\n<\/ul>\n<p>  <\/p>\n<p>Keep in mind that TFTP is a slow protocol. It works around UDP with a small block size (512K). Of course, you can increase this value, but this is a way of unstable operation.<\/p>\n<p>  <\/p>\n<p>A better solution: <\/p>\n<p>  <\/p>\n<ul>\n<li>get bootloader via tftp <\/li>\n<li>get kernel (+ initramfs) via tftp <\/li>\n<li>get main rootfs squash via http\/tftp<\/li>\n<\/ul>\n<p>  <\/p>\n<h2 id=\"how-i-do-it\">How i do it<\/h2>\n<p>  <\/p>\n<p>Steps to solve the task:<\/p>\n<p>  <\/p>\n<ol>\n<li>Add modules to initramfs<\/li>\n<li>Write my own boot script and add it to initramfs<\/li>\n<li>Make new initramfs<\/li>\n<li>Create squashfs with future rootfs<\/li>\n<li>Setup pxe server<\/li>\n<li>Run it<\/li>\n<\/ol>\n<p>  <\/p>\n<p>I used squashfs for rootfs (the simplest way is to create squashfs from installed ubuntu). Overlayfs is necessary to make rootfs writable. <\/p>\n<p>  <\/p>\n<p>Supported protocols are http\/ftp, but you can try to add others via curl\/other software. <\/p>\n<p>  <\/p>\n<h3 id=\"customize-initramfs\">Customize initramfs<\/h3>\n<p>  <\/p>\n<p>There are 2 places where you can customize initramfs in ubuntu:<\/p>\n<p>  <\/p>\n<ul>\n<li>\/etc\/initramfs-tools<\/li>\n<li>\/usr\/share\/initramfs-tools\/<\/li>\n<\/ul>\n<p>  <\/p>\n<p>I&#8217;ll use \/usr\/share\/initramfs-tools. First, I added needed support modules in initramfs:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">boozlachu@comp:~$ cat \/usr\/share\/initramfs-tools\/modules.d\/pxe overlayfs squashfs<\/code><\/pre>\n<p>  <\/p>\n<p>Next, I wrote a boot script that does all the work:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">boozlachu@comp:~$ cat \/usr\/share\/initramfs-tools\/scripts\/pxe  #!\/bin\/bash mountroot() {         maxTryCount=5         squashfsFile=\"\/tmp\/rootfs.squashfs\"         squashfsMountPoint=\"\/mnt\/ro\"         tmpfsMountPoint=\"\/mnt\/rw\"         overlayfsUppderDir=\"$tmpfsMountPoint\/upper\"         overlayfsWorkDir=\"$tmpfsMountPoint\/work\"         overlayfsDir=\"\/mnt\/overlayfs\"         tryCount=\"1\"          # run udevadm         wait_for_udev 10          # parce kernel cmdline args. rooturl needed         for x in $(cat \/proc\/cmdline); do                 case $x in                 rooturl=*)                         export rooturl=${x#rooturl=}                         ;;                 maxTryCount=*)                         export maxTryCount=${x#maxTryCount=}                         ;;                 esac         done          log_begin_msg \"Loading modules\"          modprobe squashfs || panic \"can't modprobe squashfs\"         modprobe af_packet || panic \"can't modprobe af_packet\"         modprobe overlay || panic \"can't modprobe overlayfs\"         log_success_msg \"modules loaded\"          log_begin_msg \"Configure network\"         configure_networking || panic \"Can't configure network\"         log_success_msg \"Network configured\"          log_begin_msg \"Download rootfs\"         while [ ! -f ${squashfsFile} ] &amp;&amp; [ ${tryCount} -le ${maxTryCount} ]; do                 wget ${rooturl} -O ${squashfsFile} || log_failure_msg \"Can't download rootfs, count ${tryCount}\"                 tryCount=$(( ${tryCount} + 1 ))                 sleep 0.5         done          if [ -f ${squashfsFile} ]         then                 log_success_msg \"Rootfs downloaded\"         else                 panic \"Can't download rootfs\"         fi          log_begin_msg \"Mount rootfs\"         mkdir -p $squashfsMountPoint         mount -t squashfs -o loop $squashfsFile $squashfsMountPoint || panic \"Can't mount rootfs\"         log_success_msg \"Rootfs mounted\"          log_begin_msg \"Mount tmpfs\"         mkdir -p $tmpfsMountPoint         mount -t tmpfs none $tmpfsMountPoint || panic \"Tmpfs mount failed \"         log_success_msg \"Tmpfs mounted\"          log_begin_msg \"Mount overlayfs\"         mkdir -p $overlayfsUppderDir $overlayfsWorkDir $overlayfsDir         mount -t overlay overlay -o lowerdir=$squashfsMountPoint,upperdir=$overlayfsUppderDir,workdir=$overlayfsWorkDir $overlayfsDir \\                 || panic \"Overlayfs mount failed\"         log_success_msg \"Overlayfs mounted\"          log_begin_msg \"Move tmpfs and squashfs to new root\"         mkdir -p $overlayfsDir\/$tmpfsMountPoint $overlayfsDir\/$squashfsMountPoint         mount --move $squashfsMountPoint $overlayfsDir\/$squashfsMountPoint  || panic \"squashfs move failed\"         mount --move $tmpfsMountPoint $overlayfsDir\/$tmpfsMountPoint  || panic \"tmpfs move failed\"         log_success_msg \"Tmpfs and squashfs moved\"          log_begin_msg \"Move overlayfs to new root\"         mount --move $overlayfsDir ${rootmnt}  || panic \"\" } <\/code><\/pre>\n<p>  <\/p>\n<p>The script has a lot of messages for understanding how it works.<\/p>\n<p>  <\/p>\n<p>After the modules and script, add your need to generate new initramfs:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">boozlachu@comp:~$ sudo update-initramfs -c -k all<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"creating-squashfs\">Creating squashfs<\/h2>\n<p>  <\/p>\n<p>The simplest method: <\/p>\n<p>  <\/p>\n<ul>\n<li>install ubuntu on drive <\/li>\n<li>boot from LiveCD <\/li>\n<li>create squashfs from the installed system <\/li>\n<\/ul>\n<p>  <\/p>\n<p>I don&#8217;t recommend this way for production since you&#8217;ll have a very large squashfs (not the best idea for pxe)! <\/p>\n<p>  <\/p>\n<h2 id=\"setup-bootloader-squashfs-and-pxe-server\">Setup bootloader, squashfs, and pxe server<\/h2>\n<p>  <\/p>\n<p>I use pxelinux as a pxe bootloader. It&#8217;s an easy way. My pxe servers are Debian 10, tftp-hpa,dhcpd, and lighttpd.<br \/>  I\u2019ll omit the installation details, but I\u2019ll show the important info. <\/p>\n<p>  <\/p>\n<p>TFRP server file struct (\/srv\/tftp is root dir fot tftp-hpa):<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">root@debian:\/srv\/tftp\/ubuntu# tree \/srv\/tftp\/ \/srv\/tftp\/ \u2514\u2500\u2500 ubuntu     \u251c\u2500\u2500 firmware.sq     \u251c\u2500\u2500 initrd     \u251c\u2500\u2500 ldlinux.c32     \u251c\u2500\u2500 libcom32.c32     \u251c\u2500\u2500 libutil.c32     \u251c\u2500\u2500 menu.c32     \u251c\u2500\u2500 pxelinux.bin     \u251c\u2500\u2500 pxelinux.cfg     \u2502   \u2514\u2500\u2500 default     \u251c\u2500\u2500 vesamenu.c32     \u2514\u2500\u2500 vmlinuz<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li>firmware.sq is squashfs with rootfs<\/li>\n<li>*c32 are files for pxelinux<\/li>\n<li>vmlinuz is kernel<\/li>\n<li>initrd is initramfs(which i rebuild earler)<\/li>\n<li>pxelinux.bin \u2014 main pxelinux file<\/li>\n<li>default is config for pxelinux<\/li>\n<\/ul>\n<p>  <\/p>\n<p>Bootloader config:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">root@debian:\/srv\/tftp\/ubuntu# cat \/srv\/tftp\/ubuntu\/pxelinux.cfg\/default  ui menu.c32 timeout 30 default ubuntu_pxe  font UniCyr_8x16.psf menu title PXE Special Boot Menu menu color tabmsg 37;40      #80ffffff #00000000 menu color hotsel 30;47      #40000000 #20ffffff menu color sel 30;47      #40000000 #20ffffff menu color scrollbar 30;47      #40000000 #20ffffff  LABEL ubuntu_pxe menu label  Run ubuntu pxe          kernel vmlinuz          append initrd=initrd rooturl=http:\/\/192.168.56.2\/ubuntu\/firmware.sq boot=pxe maxTryCount=10<\/code><\/pre>\n<p>  <\/p>\n<p>It\u2019s impotant to set the correct kernel parameters:<\/p>\n<p>  <\/p>\n<ul>\n<li>rooturl=<a href=\"http:\/\/192.168.56.2\/ubuntu\/firmware.sq\" rel=\"nofollow\">http:\/\/192.168.56.2\/ubuntu\/firmware.sq<\/a>, url for rootfs<\/li>\n<li>boot=pxe, use my script for boot<\/li>\n<li>maxTryCount=10, number of tries for rootfs download (optional, default value 5)<\/li>\n<\/ul>\n<p>  <\/p>\n<p>And the last one is the dhcp config:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">root@debian:\/srv\/tftp\/ubuntu# cat \/etc\/dhcp\/dhcpd.conf subnet 192.168.56.0 netmask 255.255.255.0 {         range 192.168.56.10 192.168.56.45;         option routers 192.168.56.2;         option domain-name-servers 192.168.2.1 ;         option broadcast-address 192.168.56.255;         default-lease-time 3600;         max-lease-time 7200;         # Important! Set bootloader file         filename \"ubuntu\/pxelinux.bin\";     } <\/code><\/pre>\n<p>  <\/p>\n<p>The extended variant (if the dhcp and tftp servers placed on different machines) requires the next-server option for dhcp.<\/p>\n<p>  <\/p>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>  <\/p>\n<p>This article shows you how to change the boot mode of ubuntu without any difficulties. Use it as information and write your solutions. This can be a system in the form of firmware (with squashfs), pxe, or another solution.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/513568\/\"> https:\/\/habr.com\/ru\/articles\/513568\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2 id=\"intro\">Intro<\/h2>\n<p>  <\/p>\n<p>PXE is a great solution for booting a diskless computer (or a computer without an OS installed). This method is often used for terminal stations and OS mass installation.<\/p>\n<p>  <\/p>\n<p>Stock ubuntu (16.04) in pxe-mode can mount rootfs only from NFS. But this is not a great idea: any difficulties with the network\/NFS server and the user gets problems.<\/p>\n<p>  <\/p>\n<p>In my opinion, it&#8217;s best to use other protocols, such as http\/ftp. Once booting, you will have an independent system <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-408191","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/408191","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=408191"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/408191\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=408191"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=408191"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=408191"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}