aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlo Landmeter <clandmeter@alpinelinux.org>2018-03-05 22:39:42 +0000
committerCarlo Landmeter <clandmeter@alpinelinux.org>2018-03-05 22:39:42 +0000
commitfa919cb681747c95a31ceed508282a4e8475d0bf (patch)
tree51c12187cf002b19fa137cf9a0b97ff38cf5db53
downloadalpine-netboot-fa919cb681747c95a31ceed508282a4e8475d0bf.tar.bz2
alpine-netboot-fa919cb681747c95a31ceed508282a4e8475d0bf.tar.xz
Initial commit
-rw-r--r--LICENSE21
-rw-r--r--README.md68
-rw-r--r--boot.ipxe27
-rw-r--r--html/alpinelinux-logo.svg167
-rw-r--r--html/favicon.icobin0 -> 4286 bytes
-rw-r--r--html/page.theme31
-rw-r--r--html/style.css66
-rw-r--r--html/theme.css709
-rwxr-xr-xmkindex.sh15
-rwxr-xr-xmknetboot.sh76
-rwxr-xr-xupdate-netboot.sh93
11 files changed, 1273 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e45ac6b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Carlo Landmeter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2335bf0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,68 @@
+# Alpine Linux netboot
+
+Welcome to the Alpine Linux netboot server.
+
+Netboot provides kernel initramfs and modloop images to boot over the
+network/internet. Booting from netboot is provided by the IPXE binaries
+available in alpine-ipxe `apk add alpine-ipxe` or from
+[this location](alpine-ipxe).
+
+## Boot script
+
+The default bootscript for alpine-ipxe is
+**[https://boot.alpinelinux.org/boot.ipxe](boot.ipxe)** which will automatically
+be fetched by alpine-ipxe. If you like to change this behaviour you will need to
+build your own version of [ipxe](https://ipxe.org).
+
+Some cloud providers (ie [packet.net](https://help.packet.net/technical/infrastructure/custom-ipxe))
+support the loading of custom ipxe scripts/payloads to install an operating
+system. You can chainload one of the ipxe loaders from [alpine-ipxe](alpine-ipxe).
+Don't load the boot.ipxe script directly as image verifications will fail.
+
+## Images
+
+Images are hosted in the [Images](images) directory on boot.alpinelinux.org.
+Current available images are:
+
+* **edge**
+ * [x86](images/edge/x86)
+ * [x86_64](images/edge/x86_64)
+* **latest-stable**
+ * [x86](images/latest-stable/x86)
+ * [x86_64](images/latest-stable/x86_64)
+
+## Signed images
+
+Alpine Linux images are signed and can be verified only by making use of
+[alpine-ipxe](alpine-ipxe). Using another ipxe loader will not trust our
+signatures and will result in failed boot.
+
+## Boot options
+
+### BIOS
+
+* [pxe.lkrn](alpine-ipxe/ipxe.lkrn) - Linux kernel image that can be used by a bootloader/qemu
+* [pxe.pxe](alpine-ipxe/ipxe.pxe) - PXE image for chainloading from a PXE environment
+* [undionly.kpxe](alpine-ipxe/undionly.kpxe) - PXE image with UNDI support
+* [ipxe.iso](alpine-ipxe/ipxe.iso) - ISO image to boot from any regular system
+
+### UEFI
+
+* [ipxe.efi](alpine-ipxe/ipxe.efi) x86_64 UEFI executable
+
+## Updates
+
+Netboot images are updated every night automatically if any package in the
+dependecy tree (kernel and alpine-base) has been updated. Regular packages are
+updated automatically via our package repositories.
+
+## Testing netboot
+
+The easiest way to test is by using Qemu directly with the ipxe kernel image.
+
+`apk add qemu-system-x86_64 alpine-ipxe`
+
+`qemu-system-x86_64 -m 512M -enable-kvm -kernel /usr/share/alpine-ipxe/ipxe.lkrn -curses`
+
+**NOTE**: you need a minimum of 256M of memory to boot alpine in network mode
+due to the size of our initramfs and modloop (kernel modules).
diff --git a/boot.ipxe b/boot.ipxe
new file mode 100644
index 0000000..57127e4
--- /dev/null
+++ b/boot.ipxe
@@ -0,0 +1,27 @@
+#!ipxe
+
+set os Alpine Linux
+cpuid --ext 29 && set arch x86_64 || set arch x86
+
+imgtrust --permanent
+
+menu ${os} [ ${arch} ]
+item latest-stable Latest stable
+item edge Edge (development)
+choose version || goto alpine_exit
+goto boot
+
+:boot
+set img-url http://boot.alpinelinux.org/images/${version}/${arch}
+set repo-url http://dl-cdn.alpinelinux.org/alpine/${version}/main
+imgfree
+kernel ${img-url}/vmlinuz-vanilla alpine_repo=${repo-url} modules=loop,squashfs modloop=${img-url}/modloop-vanilla quiet nomodeset
+imgverify vmlinuz-vanilla ${img-url}/vmlinuz-vanilla.sig
+initrd ${img-url}/initramfs-vanilla
+imgverify initramfs-vanilla ${img-url}/initramfs-vanilla.sig
+boot
+goto alpine_exit
+
+:alpine_exit
+clear menu
+exit 0
diff --git a/html/alpinelinux-logo.svg b/html/alpinelinux-logo.svg
new file mode 100644
index 0000000..70f2f60
--- /dev/null
+++ b/html/alpinelinux-logo.svg
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ width="665.16876"
+ height="161.78787"
+ xml:space="preserve"
+ sodipodi:docname="alpinelinux-logo.svg"><metadata
+ id="metadata8"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs6"><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath16"><path
+ d="M 0,560 960,560 960,0 0,0 0,560 z"
+ id="path18"
+ inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1595"
+ inkscape:window-height="964"
+ id="namedview4"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:zoom="0.33333333"
+ inkscape:cx="-197.05676"
+ inkscape:cy="-80.4375"
+ inkscape:window-x="276"
+ inkscape:window-y="233"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="g10" /><g
+ id="g10"
+ inkscape:groupmode="layer"
+ inkscape:label="Alpine_Linux_logo_v4"
+ transform="matrix(1.25,0,0,-1.25,-267.55675,592.22537)"><g
+ id="g20"
+ transform="translate(686.7844,397.9583)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 c -3.74,6.413 -3.73,19.372 0.023,26.161 1.64,2.969 6.622,9.559 28.367,9.559 4.468,0 7.739,-0.229 10.148,-0.554 5.278,-0.71 9.297,-2.509 9.297,-7.425 0,-6.49 -9.565,-6.55 -9.565,-6.55 l -20.27,0 C 9.392,21.191 8.734,9.287 8.734,9.287 l 9.17,0 20.366,0 c 10.375,0 21.125,4.649 21.125,18.258 0,9.047 -5.207,15.135 -13.71,17.468 -8.498,2.332 -11.809,2.206 -23.391,1.998 C 13.02,46.845 7.679,44.81 4.305,43.752 -1.609,41.896 -6.907,38.432 -10.48,31.966 -16.297,21.438 -16.244,4.03 -10.365,-6.047 -4.08,-16.821 6.696,-22.587 19.723,-22.597 l 39.672,0 10e-4,11.943 -39.714,0 C 8.246,-10.688 2.571,-4.408 0,0"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path22"
+ inkscape:connector-curvature="0" /></g><g
+ id="g24"
+ transform="translate(441.9298,442.9648)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 c -10.527,5.817 -27.936,5.764 -38.013,-0.115 -14.384,-8.391 -19.841,-24.786 -14.594,-43.858 2.693,-9.79 9.965,-17.002 21.03,-20.855 7.818,-2.723 15.012,-2.801 15.31,-2.803 l -0.015,12 c -0.207,10e-4 -20.756,0.305 -24.755,14.842 -5.16,18.758 3.468,27.041 9.071,30.309 6.413,3.74 19.372,3.73 26.161,-0.023 7.212,-3.985 7.733,-12.297 7.733,-25.513 l 0,-24.358 c 0,-8.608 12,-9.171 12,-9.171 l 0,9.171 0,24.358 c 0,12.618 0,28.319 -13.928,36.016"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path26"
+ inkscape:connector-curvature="0" /></g><g
+ id="g28"
+ transform="translate(597.6101,375.3665)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 0,37.405 c 0.011,13.027 5.776,23.803 16.55,30.088 10.078,5.878 27.486,5.932 38.013,0.115 13.928,-7.697 13.928,-23.399 13.928,-36.016 l 0,-24.319 0,-9.171 c 0,0 -12,0.563 -12,9.171 l 0,24.319 c 0,13.216 -0.521,21.528 -7.733,25.513 C 41.969,60.858 29.01,60.868 22.597,57.128 18.189,54.557 11.909,48.882 11.943,37.446 l 0,-37.447 L 0,0 z"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path30"
+ inkscape:connector-curvature="0" /></g><g
+ id="g32"
+ transform="translate(579.8309,375.3661)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 0,47.562 0,9.171 c 0,0 11.904,-0.658 11.904,-9.267 L 11.904,0 0,0 z"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path34"
+ inkscape:connector-curvature="0" /></g><g
+ id="g36"
+ transform="translate(591.7351,443.8518)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 0,-2.028 0,-9.171 c 0,0 -11.904,0.658 -11.904,9.267 L -11.904,0 0,0 z"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path38"
+ inkscape:connector-curvature="0" /></g><g
+ id="g40"
+ transform="translate(519.3928,442.6805)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 c 10.527,5.817 27.936,5.764 38.013,-0.115 14.384,-8.391 19.841,-24.786 14.594,-43.858 -2.693,-9.79 -9.965,-17.002 -21.03,-20.855 -7.818,-2.723 -15.007,-2.447 -15.305,-2.449 l 0.01,11.899 c 0.207,10e-4 20.756,0.052 24.755,14.589 5.16,18.758 -3.468,27.041 -9.071,30.309 -6.413,3.74 -19.372,3.73 -26.161,-0.023 -7.212,-3.985 -7.733,-12.297 -7.733,-25.513 l 0,-12.612 c 0,-8.608 -12,-9.17 -12,-9.17 l 0,9.17 0,12.612 c 0,12.618 0,28.319 13.928,36.016"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path42"
+ inkscape:connector-curvature="0" /></g><g
+ id="g44"
+ transform="translate(517.3693,344.6278)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 0,30.505 0,9.17 c 0,0 -11.904,-0.658 -11.904,-9.266 L -11.904,0 0,0 z"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path46"
+ inkscape:connector-curvature="0" /></g><g
+ id="g48"
+ transform="translate(473.349,473.7803)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 0,-32.359 0,-9.17 c 0,0 -11.904,0.658 -11.904,9.266 L -11.904,0 0,0 z"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path50"
+ inkscape:connector-curvature="0" /></g><g
+ id="g52"
+ transform="translate(474.9603,402.1447)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 c -1.039,3.777 -1.519,7.129 -1.577,10.101 l -0.034,10.255 c 0,8.608 -11.913,9.171 -11.913,9.171 l 0,-9.171 0,-10.193 c 0.037,-4.24 0.68,-8.714 1.954,-13.347 2.693,-9.79 9.966,-17.002 21.03,-20.855 7.818,-2.723 14.992,-2.743 15.289,-2.745 l 0.006,11.942 C 24.548,-14.841 3.999,-14.537 0,0"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path54"
+ inkscape:connector-curvature="0" /></g><g
+ id="g56"
+ transform="translate(268.1394,393.2718)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="M 0,0 0,15.687 -11.296,4.379 C -10.079,3.532 -8.932,2.836 -7.853,2.27 -6.774,1.703 -5.764,1.265 -4.823,0.932 -3.882,0.598 -3.009,0.37 -2.206,0.222 -1.402,0.075 -0.667,0.009 0,0 m 57.751,1.304 c 0.02,-0.017 0.13,-0.11 0.333,-0.239 0.204,-0.13 0.502,-0.297 0.898,-0.462 0.395,-0.164 0.889,-0.327 1.485,-0.448 0.596,-0.122 1.294,-0.202 2.098,-0.202 0.671,0 1.411,0.059 2.222,0.2 0.812,0.142 1.693,0.367 2.645,0.699 0.953,0.333 1.976,0.773 3.07,1.344 1.094,0.572 2.259,1.276 3.495,2.136 L 65.425,12.729 37.015,41.245 24.549,28.776 7.733,46.117 -34.471,4.39 c 1.235,-0.86 2.398,-1.564 3.491,-2.136 1.093,-0.571 2.115,-1.011 3.067,-1.344 0.951,-0.332 1.832,-0.557 2.643,-0.698 0.81,-0.142 1.55,-0.201 2.22,-0.201 0.804,0 1.502,0.08 2.097,0.202 0.596,0.121 1.089,0.284 1.485,0.449 0.396,0.164 0.693,0.331 0.897,0.461 0.204,0.13 0.314,0.223 0.334,0.24 L 0.815,20.415 7.628,26.948 26.494,8.082 33.085,1.304 c 0.02,-0.017 0.13,-0.11 0.334,-0.239 0.204,-0.13 0.501,-0.297 0.897,-0.462 0.396,-0.164 0.89,-0.327 1.485,-0.448 0.596,-0.122 1.295,-0.202 2.099,-0.202 0.67,0 1.411,0.059 2.222,0.2 0.811,0.142 1.693,0.367 2.645,0.699 0.952,0.333 1.975,0.773 3.069,1.344 1.094,0.572 2.259,1.276 3.495,2.136 L 34.192,19.157 37.01,21.975 50.111,8.874 57.751,1.304 M 57.588,80.32 94.807,15.838 57.588,-48.644 l -74.463,0 -37.219,64.482 37.219,64.482 74.463,0 z"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path58"
+ inkscape:connector-curvature="0" /></g><g
+ id="g60"
+ transform="translate(302.5041,412.251)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="M 0,0 -9.913,9.895 -9.208,10.604 0.775,0.73 0,0 z"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path62"
+ inkscape:connector-curvature="0" /></g><g
+ id="g64"
+ transform="translate(528.4338,353.235)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 0,22.161 -2,0 L -2,0 c 0,-4.295 3.35,-8.885 12.75,-8.885 l 15.25,0 0,2 -15.25,0 C 0.775,-6.885 0,-1.615 0,0"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path66"
+ inkscape:connector-curvature="0" /></g><path
+ d="m 561.073,344.35 2,0 0,22.787 -2,0 0,-22.787 z"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path68"
+ inkscape:connector-curvature="0" /><path
+ d="m 561.073,368.358 2,0 0,2.992 -2,0 0,-2.992 z"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path70"
+ inkscape:connector-curvature="0" /><g
+ id="g72"
+ transform="translate(664.6232,367.1373)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 -2.634,0 -8.469,-9.888 -8.481,9.888 -2.634,0 9.796,-11.428 -9.729,-11.359 2.62,0 8.422,9.827 8.423,-9.827 2.647,0 -9.75,11.367 L 0,0 z"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path74"
+ inkscape:connector-curvature="0" /></g><g
+ id="g76"
+ transform="translate(634.3527,353.11)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="M 0,0 C 0,-0.691 -0.366,-6.76 -13.063,-6.76 -25.637,-6.76 -26,-0.691 -26,0 l 0,14.027 -2,0 L -28,0 c 0,-0.896 0.419,-8.76 14.937,-8.76 C 1.577,-8.76 2,-0.896 2,0 l 0,14.027 -2,0 L 0,0 z"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path78"
+ inkscape:connector-curvature="0" /></g><g
+ id="g80"
+ transform="translate(584.7756,367.1373)"
+ style="fill:#0d597f;fill-opacity:1"><path
+ d="m 0,0 c -14.64,0 -15.063,-7.863 -15.063,-8.76 l 0,-14.027 2,0 0,14.027 c 0,0.692 0.367,6.76 13.063,6.76 12.574,0 12.938,-6.068 12.938,-6.76 l 0,-14.027 2,0 0,14.027 C 14.938,-7.863 14.519,0 0,0"
+ style="fill:#0d597f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path82"
+ inkscape:connector-curvature="0" /></g></g></svg> \ No newline at end of file
diff --git a/html/favicon.ico b/html/favicon.ico
new file mode 100644
index 0000000..471bba3
--- /dev/null
+++ b/html/favicon.ico
Binary files differ
diff --git a/html/page.theme b/html/page.theme
new file mode 100644
index 0000000..664ae04
--- /dev/null
+++ b/html/page.theme
@@ -0,0 +1,31 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="description" content="Alpine Linux netboot">
+ <title>Alpine Linux netboot</title>
+ <link rel="stylesheet" href="html/theme.css">
+ <link rel="stylesheet" href="html/style.css">
+ <link rel="shortcut icon" href="html/favicon.ico" />
+</head>
+<body>
+ <div id="wrapper">
+ <header>
+ <div class="g-4-24">
+ <div class="logo">
+ <a href="/"><img src="html/alpinelinux-logo.svg" alt="Alpine Logo" class="img-block"></a>
+ </div>
+ </div>
+ <div class="g-20-24">
+ </div>
+ </header>
+ <div class="markdown-body">
+ <?theme body?>
+ </div>
+ <footer>
+ <span>© Copyright 2018 Alpine Linux Development Team all rights reserved</span> | <span>Page generated <?theme date?> GMT</span>
+ </footer>
+ </div>
+</body>
+</html>
diff --git a/html/style.css b/html/style.css
new file mode 100644
index 0000000..5a736ad
--- /dev/null
+++ b/html/style.css
@@ -0,0 +1,66 @@
+html, body {
+ margin: 0;
+ padding: 0;
+ height: 100%;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial,
+ sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+ color: #526066;
+}
+
+div#wrapper {
+ min-height: 100%;
+ position: relative;
+}
+
+header {
+ border-bottom: 1px solid #eaecef;
+}
+
+div.logo {
+ padding: 1em;
+}
+
+.img-block {
+ max-width: 100%;
+ height: auto;
+ display: block;
+}
+
+div.markdown-body {
+ box-sizing: border-box;
+ min-width: 200px;
+ max-width: 980px;
+ margin: 0 auto;
+ padding: 30px;
+ padding-bottom: 50px;
+}
+
+div.g-4-24 {
+ width: 16.6667%;
+}
+
+div.g-20-24 {
+ width: 83.3333%;
+}
+
+footer {
+ background: #111;
+ color: #888;
+ text-align: center;
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ padding-top: 0.6em;
+ padding-bottom: 0.6em;
+ font-size: 0.6em;
+}
+
+.pointer {
+ cursor: pointer;
+}
+
+@media (max-width: 63.999em) {
+ .logo img {
+ max-width: 16em;
+ }
+}
diff --git a/html/theme.css b/html/theme.css
new file mode 100644
index 0000000..e197e59
--- /dev/null
+++ b/html/theme.css
@@ -0,0 +1,709 @@
+@font-face {
+ font-family: octicons-link;
+ src: url(data:font/woff;charset=utf-8;base64,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) format('woff');
+}
+
+.markdown-body {
+ -ms-text-size-adjust: 100%;
+ -webkit-text-size-adjust: 100%;
+ line-height: 1.5;
+ color: #24292e;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+ font-size: 16px;
+ line-height: 1.5;
+ word-wrap: break-word;
+}
+
+.markdown-body .pl-c {
+ color: #6a737d;
+}
+
+.markdown-body .pl-c1,
+.markdown-body .pl-s .pl-v {
+ color: #005cc5;
+}
+
+.markdown-body .pl-e,
+.markdown-body .pl-en {
+ color: #6f42c1;
+}
+
+.markdown-body .pl-smi,
+.markdown-body .pl-s .pl-s1 {
+ color: #24292e;
+}
+
+.markdown-body .pl-ent {
+ color: #22863a;
+}
+
+.markdown-body .pl-k {
+ color: #d73a49;
+}
+
+.markdown-body .pl-s,
+.markdown-body .pl-pds,
+.markdown-body .pl-s .pl-pse .pl-s1,
+.markdown-body .pl-sr,
+.markdown-body .pl-sr .pl-cce,
+.markdown-body .pl-sr .pl-sre,
+.markdown-body .pl-sr .pl-sra {
+ color: #032f62;
+}
+
+.markdown-body .pl-v,
+.markdown-body .pl-smw {
+ color: #e36209;
+}
+
+.markdown-body .pl-bu {
+ color: #b31d28;
+}
+
+.markdown-body .pl-ii {
+ color: #fafbfc;
+ background-color: #b31d28;
+}
+
+.markdown-body .pl-c2 {
+ color: #fafbfc;
+ background-color: #d73a49;
+}
+
+.markdown-body .pl-c2::before {
+ content: "^M";
+}
+
+.markdown-body .pl-sr .pl-cce {
+ font-weight: bold;
+ color: #22863a;
+}
+
+.markdown-body .pl-ml {
+ color: #735c0f;
+}
+
+.markdown-body .pl-mh,
+.markdown-body .pl-mh .pl-en,
+.markdown-body .pl-ms {
+ font-weight: bold;
+ color: #005cc5;
+}
+
+.markdown-body .pl-mi {
+ font-style: italic;
+ color: #24292e;
+}
+
+.markdown-body .pl-mb {
+ font-weight: bold;
+ color: #24292e;
+}
+
+.markdown-body .pl-md {
+ color: #b31d28;
+ background-color: #ffeef0;
+}
+
+.markdown-body .pl-mi1 {
+ color: #22863a;
+ background-color: #f0fff4;
+}
+
+.markdown-body .pl-mc {
+ color: #e36209;
+ background-color: #ffebda;
+}
+
+.markdown-body .pl-mi2 {
+ color: #f6f8fa;
+ background-color: #005cc5;
+}
+
+.markdown-body .pl-mdr {
+ font-weight: bold;
+ color: #6f42c1;
+}
+
+.markdown-body .pl-ba {
+ color: #586069;
+}
+
+.markdown-body .pl-sg {
+ color: #959da5;
+}
+
+.markdown-body .pl-corl {
+ text-decoration: underline;
+ color: #032f62;
+}
+
+.markdown-body .octicon {
+ display: inline-block;
+ vertical-align: text-top;
+ fill: currentColor;
+}
+
+.markdown-body a {
+ background-color: transparent;
+ -webkit-text-decoration-skip: objects;
+}
+
+.markdown-body a:active,
+.markdown-body a:hover {
+ outline-width: 0;
+}
+
+.markdown-body strong {
+ font-weight: inherit;
+}
+
+.markdown-body strong {
+ font-weight: bolder;
+}
+
+.markdown-body h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+.markdown-body img {
+ border-style: none;
+}
+
+.markdown-body svg:not(:root) {
+ overflow: hidden;
+}
+
+.markdown-body code,
+.markdown-body kbd,
+.markdown-body pre {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+
+.markdown-body hr {
+ box-sizing: content-box;
+ height: 0;
+ overflow: visible;
+}
+
+.markdown-body input {
+ font: inherit;
+ margin: 0;
+}
+
+.markdown-body input {
+ overflow: visible;
+}
+
+.markdown-body [type="checkbox"] {
+ box-sizing: border-box;
+ padding: 0;
+}
+
+.markdown-body * {
+ box-sizing: border-box;
+}
+
+.markdown-body input {
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+
+.markdown-body a {
+ color: #0366d6;
+ text-decoration: none;
+}
+
+.markdown-body a:hover {
+ text-decoration: underline;
+}
+
+.markdown-body strong {
+ font-weight: 600;
+}
+
+.markdown-body hr {
+ height: 0;
+ margin: 15px 0;
+ overflow: hidden;
+ background: transparent;
+ border: 0;
+ border-bottom: 1px solid #dfe2e5;
+}
+
+.markdown-body hr::before {
+ display: table;
+ content: "";
+}
+
+.markdown-body hr::after {
+ display: table;
+ clear: both;
+ content: "";
+}
+
+.markdown-body table {
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+
+.markdown-body td,
+.markdown-body th {
+ padding: 0;
+}
+
+.markdown-body h1,
+.markdown-body h2,
+.markdown-body h3,
+.markdown-body h4,
+.markdown-body h5,
+.markdown-body h6 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.markdown-body h1 {
+ font-size: 32px;
+ font-weight: 600;
+}
+
+.markdown-body h2 {
+ font-size: 24px;
+ font-weight: 600;
+}
+
+.markdown-body h3 {
+ font-size: 20px;
+ font-weight: 600;
+}
+
+.markdown-body h4 {
+ font-size: 16px;
+ font-weight: 600;
+}
+
+.markdown-body h5 {
+ font-size: 14px;
+ font-weight: 600;
+}
+
+.markdown-body h6 {
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.markdown-body p {
+ margin-top: 0;
+ margin-bottom: 10px;
+}
+
+.markdown-body blockquote {
+ margin: 0;
+}
+
+.markdown-body ul,
+.markdown-body ol {
+ padding-left: 0;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.markdown-body ol ol,
+.markdown-body ul ol {
+ list-style-type: lower-roman;
+}
+
+.markdown-body ul ul ol,
+.markdown-body ul ol ol,
+.markdown-body ol ul ol,
+.markdown-body ol ol ol {
+ list-style-type: lower-alpha;
+}
+
+.markdown-body dd {
+ margin-left: 0;
+}
+
+.markdown-body code {
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 12px;
+}
+
+.markdown-body pre {
+ margin-top: 0;
+ margin-bottom: 0;
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 12px;
+}
+
+.markdown-body .octicon {
+ vertical-align: text-bottom;
+}
+
+.markdown-body .pl-0 {
+ padding-left: 0 !important;
+}
+
+.markdown-body .pl-1 {
+ padding-left: 4px !important;
+}
+
+.markdown-body .pl-2 {
+ padding-left: 8px !important;
+}
+
+.markdown-body .pl-3 {
+ padding-left: 16px !important;
+}
+
+.markdown-body .pl-4 {
+ padding-left: 24px !important;
+}
+
+.markdown-body .pl-5 {
+ padding-left: 32px !important;
+}
+
+.markdown-body .pl-6 {
+ padding-left: 40px !important;
+}
+
+.markdown-body::before {
+ display: table;
+ content: "";
+}
+
+.markdown-body::after {
+ display: table;
+ clear: both;
+ content: "";
+}
+
+.markdown-body>*:first-child {
+ margin-top: 0 !important;
+}
+
+.markdown-body>*:last-child {
+ margin-bottom: 0 !important;
+}
+
+.markdown-body a:not([href]) {
+ color: inherit;
+ text-decoration: none;
+}
+
+.markdown-body .anchor {
+ float: left;
+ padding-right: 4px;
+ margin-left: -20px;
+ line-height: 1;
+}
+
+.markdown-body .anchor:focus {
+ outline: none;
+}
+
+.markdown-body p,
+.markdown-body blockquote,
+.markdown-body ul,
+.markdown-body ol,
+.markdown-body dl,
+.markdown-body table,
+.markdown-body pre {
+ margin-top: 0;
+ margin-bottom: 16px;
+}
+
+.markdown-body hr {
+ height: 0.25em;
+ padding: 0;
+ margin: 24px 0;
+ background-color: #e1e4e8;
+ border: 0;
+}
+
+.markdown-body blockquote {
+ padding: 0 1em;
+ color: #6a737d;
+ border-left: 0.25em solid #dfe2e5;
+}
+
+.markdown-body blockquote>:first-child {
+ margin-top: 0;
+}
+
+.markdown-body blockquote>:last-child {
+ margin-bottom: 0;
+}
+
+.markdown-body kbd {
+ display: inline-block;
+ padding: 3px 5px;
+ font-size: 11px;
+ line-height: 10px;
+ color: #444d56;
+ vertical-align: middle;
+ background-color: #fafbfc;
+ border: solid 1px #c6cbd1;
+ border-bottom-color: #959da5;
+ border-radius: 3px;
+ box-shadow: inset 0 -1px 0 #959da5;
+}
+
+.markdown-body h1,
+.markdown-body h2,
+.markdown-body h3,
+.markdown-body h4,
+.markdown-body h5,
+.markdown-body h6 {
+ margin-top: 24px;
+ margin-bottom: 16px;
+ font-weight: 600;
+ line-height: 1.25;
+}
+
+.markdown-body h1 .octicon-link,
+.markdown-body h2 .octicon-link,
+.markdown-body h3 .octicon-link,
+.markdown-body h4 .octicon-link,
+.markdown-body h5 .octicon-link,
+.markdown-body h6 .octicon-link {
+ color: #1b1f23;
+ vertical-align: middle;
+ visibility: hidden;
+}
+
+.markdown-body h1:hover .anchor,
+.markdown-body h2:hover .anchor,
+.markdown-body h3:hover .anchor,
+.markdown-body h4:hover .anchor,
+.markdown-body h5:hover .anchor,
+.markdown-body h6:hover .anchor {
+ text-decoration: none;
+}
+
+.markdown-body h1:hover .anchor .octicon-link,
+.markdown-body h2:hover .anchor .octicon-link,
+.markdown-body h3:hover .anchor .octicon-link,
+.markdown-body h4:hover .anchor .octicon-link,
+.markdown-body h5:hover .anchor .octicon-link,
+.markdown-body h6:hover .anchor .octicon-link {
+ visibility: visible;
+}
+
+.markdown-body h1 {
+ padding-bottom: 0.3em;
+ font-size: 2em;
+ border-bottom: 1px solid #eaecef;
+}
+
+.markdown-body h2 {
+ padding-bottom: 0.3em;
+ font-size: 1.5em;
+ border-bottom: 1px solid #eaecef;
+}
+
+.markdown-body h3 {
+ font-size: 1.25em;
+}
+
+.markdown-body h4 {
+ font-size: 1em;
+}
+
+.markdown-body h5 {
+ font-size: 0.875em;
+}
+
+.markdown-body h6 {
+ font-size: 0.85em;
+ color: #6a737d;
+}
+
+.markdown-body ul,
+.markdown-body ol {
+ padding-left: 2em;
+}
+
+.markdown-body ul ul,
+.markdown-body ul ol,
+.markdown-body ol ol,
+.markdown-body ol ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.markdown-body li>p {
+ margin-top: 16px;
+}
+
+.markdown-body li+li {
+ margin-top: 0.25em;
+}
+
+.markdown-body dl {
+ padding: 0;
+}
+
+.markdown-body dl dt {
+ padding: 0;
+ margin-top: 16px;
+ font-size: 1em;
+ font-style: italic;
+ font-weight: 600;
+}
+
+.markdown-body dl dd {
+ padding: 0 16px;
+ margin-bottom: 16px;
+}
+
+.markdown-body table {
+ display: block;
+ width: 100%;
+ overflow: auto;
+}
+
+.markdown-body table th {
+ font-weight: 600;
+}
+
+.markdown-body table th,
+.markdown-body table td {
+ padding: 6px 13px;
+ border: 1px solid #dfe2e5;
+}
+
+.markdown-body table tr {
+ background-color: #fff;
+ border-top: 1px solid #c6cbd1;
+}
+
+.markdown-body table tr:nth-child(2n) {
+ background-color: #f6f8fa;
+}
+
+.markdown-body img {
+ max-width: 100%;
+ box-sizing: content-box;
+ background-color: #fff;
+}
+
+.markdown-body img[align=right] {
+ padding-left: 20px;
+}
+
+.markdown-body img[align=left] {
+ padding-right: 20px;
+}
+
+.markdown-body code {
+ padding: 0;
+ padding-top: 0.2em;
+ padding-bottom: 0.2em;
+ margin: 0;
+ font-size: 85%;
+ background-color: rgba(27,31,35,0.05);
+ border-radius: 3px;
+}
+
+.markdown-body code::before,
+.markdown-body code::after {
+ letter-spacing: -0.2em;
+ content: "\00a0";
+}
+
+.markdown-body pre {
+ word-wrap: normal;
+}
+
+.markdown-body pre>code {
+ padding: 0;
+ margin: 0;
+ font-size: 100%;
+ word-break: normal;
+ white-space: pre;
+ background: transparent;
+ border: 0;
+}
+
+.markdown-body .highlight {
+ margin-bottom: 16px;
+}
+
+.markdown-body .highlight pre {
+ margin-bottom: 0;
+ word-break: normal;
+}
+
+.markdown-body .highlight pre,
+.markdown-body pre {
+ padding: 16px;
+ overflow: auto;
+ font-size: 85%;
+ line-height: 1.45;
+ background-color: #f6f8fa;
+ border-radius: 3px;
+}
+
+.markdown-body pre code {
+ display: inline;
+ max-width: auto;
+ padding: 0;
+ margin: 0;
+ overflow: visible;
+ line-height: inherit;
+ word-wrap: normal;
+ background-color: transparent;
+ border: 0;
+}
+
+.markdown-body pre code::before,
+.markdown-body pre code::after {
+ content: normal;
+}
+
+.markdown-body .full-commit .btn-outline:not(:disabled):hover {
+ color: #005cc5;
+ border-color: #005cc5;
+}
+
+.markdown-body kbd {
+ display: inline-block;
+ padding: 3px 5px;
+ font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ line-height: 10px;
+ color: #444d56;
+ vertical-align: middle;
+ background-color: #fafbfc;
+ border: solid 1px #d1d5da;
+ border-bottom-color: #c6cbd1;
+ border-radius: 3px;
+ box-shadow: inset 0 -1px 0 #c6cbd1;
+}
+
+.markdown-body :checked+.radio-label {
+ position: relative;
+ z-index: 1;
+ border-color: #0366d6;
+}
+
+.markdown-body .task-list-item {
+ list-style-type: none;
+}
+
+.markdown-body .task-list-item+.task-list-item {
+ margin-top: 3px;
+}
+
+.markdown-body .task-list-item input {
+ margin: 0 0.2em 0.25em -1.6em;
+ vertical-align: middle;
+}
+
+.markdown-body hr {
+ border-bottom-color: #eee;
+}
diff --git a/mkindex.sh b/mkindex.sh
new file mode 100755
index 0000000..c6dbb74
--- /dev/null
+++ b/mkindex.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+htmldir="/var/www/localhost/htdocs"
+
+if ! command -v discount-theme >/dev/null 2>&1; then
+ echo "Cannot find discount-theme please install discount"
+ exit 1
+fi
+
+for i in html boot.ipxe; do
+ [ -L "$htmldir/$i" ] || ln -s "$(realpath $i)" "$htmldir"
+done
+
+discount-theme -t html/page.theme \
+ -o "$htmldir"/index.html README.md
diff --git a/mknetboot.sh b/mknetboot.sh
new file mode 100755
index 0000000..91087de
--- /dev/null
+++ b/mknetboot.sh
@@ -0,0 +1,76 @@
+#!/bin/sh -e
+
+ARCH=$(apk --print-arch)
+FLAVOR="vanilla"
+FEATURE="base squashfs network zfs"
+PACKAGE="spl-vanilla zfs-vanilla"
+OUTDIR="$PWD/out"
+RELEASE="edge"
+MIRROR="http://dl-cdn.alpinelinux.org/alpine"
+
+usage() {
+ local ws=$(printf %${#0}s)
+ cat <<-EOF
+
+ $0 [--arch ARCH] [--flavor FLAVOR] [--feature FEATURE]
+ $ws [--outdir OUTDIR] [--release RELEASE] [--repository REPO]
+ $0 --help
+
+ options:
+ --arch Specify which architecture images to build
+ --flavor Specify which kernel flavor images to build
+ --feature Specify which initramfs features to include
+ --package Additional module or firmware package
+ --outdir Specify directory for the created images
+ --release Build images for specified release from main repository
+ --repository Package repository to use (overides --release)
+ --extra-repository Add repository to search packages from (overides --release)
+
+ EOF
+}
+
+# parse parameters
+while [ $# -gt 0 ]; do
+ opt="$1"
+ shift
+ case "$opt" in
+ --arch) ARCH="$1"; shift ;;
+ --flavor) FLAVOR="$1"; shift ;;
+ --feature) FEATURE="$1"; shift ;;
+ --outdir) OUTDIR="$1"; shift ;;
+ --release) RELEASE="$1"; shift ;;
+ --repository) REPO="$1"; shift ;;
+ --extra-repository) EXTRAREPO="$EXTRAREPO $1"; shift ;;
+ --) break ;;
+ -*) usage; exit 1;;
+ esac
+done
+
+rm -rf "$OUTDIR"
+mkdir -p "$OUTDIR"
+
+REPOFILE=$(mktemp)
+DEFAULT_REPO="$MIRROR/$RELEASE/main"
+echo "${REPO:-$DEFAULT_REPO}" >> "$REPOFILE"
+for repo in $EXTRAREPO; do
+ echo "$repo" >> "$REPOFILE"
+done
+
+echo "Creating netboot image: $RELEASE/$ARCH/$FLAVOR"
+
+update-kernel \
+ --arch "$ARCH" \
+ --flavor "$FLAVOR" \
+ --feature "$FEATURE" \
+ --package "$PACKAGE" \
+ --repositories-file "$REPOFILE" \
+ "$OUTDIR"
+
+# older vanilla kernels do not have the flavor appended.
+for file in vmlinuz config System.map; do
+ if [ -f "$OUTDIR"/$file ]; then
+ mv "$OUTDIR"/$file "$OUTDIR"/$file-"$FLAVOR"
+ fi
+done
+
+rm -f "$REPOFILE"
diff --git a/update-netboot.sh b/update-netboot.sh
new file mode 100755
index 0000000..a23677a
--- /dev/null
+++ b/update-netboot.sh
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+REPO="http://dl-cdn.alpinelinux.org/alpine"
+BRANCHES="edge latest-stable"
+ARCHS="x86 x86_64"
+IMGDIR="/var/www/localhost/htdocs/images"
+
+# CA Settings
+CA_CRT="/etc/ssl/alpine-netboot-ca/ca.crt"
+SIGN_CRT="/etc/ssl/alpine-netboot-ca/codesign.crt"
+SIGN_KEY="/etc/ssl/alpine-netboot-ca/codesign.key"
+PASS_FILE="/etc/ssl/alpine-netboot-ca/passwd"
+
+if [ -f "/lib/libalpine.sh" ]; then
+ . /lib/libalpine.sh
+else
+ echo "Error: cannot find libalpine.sh" >&2
+ exit 1
+fi
+
+CACHE_DIR="/var/cache/alpine-netboot"
+APK="apk --no-cache --repositories-file /dev/null"
+
+compare_files() {
+ [ -f "$1" ] || return 1
+ [ -f "$2" ] || return 1
+ diff -q "$1" "$2" > /dev/null 2>&1
+}
+
+# list all runtime depencencies for alpine-base
+resolve_base() {
+ local branch="$1"
+ local arch="$2"
+ ALPINE_BASE=$($APK --arch $arch -X $REPO/$branch/main fetch -R --simulate alpine-base 2> /dev/null)
+ [ "$?" = "0" ] || die "Failed to get base dependency tree"
+ echo "$ALPINE_BASE" | grep -v '^fetch' | cut -d' ' -f2
+}
+
+# find the latest kernel and firmware.
+# kernel/firmware deps are not interesting so we do not resolve the tree.
+get_latest_kernel() {
+ local branch="$1"
+ local arch="$2"
+ KERNEL=$($APK --arch $arch -X $REPO/$branch/main search -x linux-vanilla linux-firmware)
+ [ "$?" = "0" ] || die "Failed to get kernel version"
+ echo "$KERNEL" | grep -v '^fetch'
+}
+
+sign_images() {
+ local imgdir="$1"
+ local img
+ for img in vmlinuz initramfs; do
+ local file=$(realpath $imgdir/*${img}*)
+ echo "Signing image: $file"
+ openssl cms -sign -binary -noattr -in "$file" \
+ -signer "$SIGN_CRT" -inkey "$SIGN_KEY" \
+ -certfile "$CA_CRT" \
+ -outform DER -out "$file".sig \
+ -passin file:"$PASS_FILE"
+ done
+}
+
+
+#############
+# M a i n #
+#############
+
+mkdir -p "$CACHE_DIR"
+tmpfile=$(mktemp)
+tmpdir=$(mktemp -d)
+
+for branch in $BRANCHES; do
+ mkdir -p "$IMGDIR"/$branch
+ for arch in $ARCHS; do
+ echo "Checking: $branch/$arch"
+ for i in $(resolve_base $branch $arch && get_latest_kernel $branch $arch); do
+ echo "$i" >> $tmpfile
+ done
+ sort $tmpfile -o $tmpfile
+ if ! compare_files $tmpfile "$CACHE_DIR"/$branch-$arch.lst; then
+ echo "Dependencies updated for: $branch/$arch"
+ ./mknetboot.sh --release "$branch" --arch "$arch" --outdir "$tmpdir"
+ (cd "$tmpdir" && sha512sum * > alpine-netboot-$branch-$arch.sha512)
+ sign_images "$tmpdir"
+ rm -rf "$IMGDIR"/$branch/$arch
+ mv "$tmpdir" "$IMGDIR"/$branch/$arch
+ mv "$tmpfile" "$CACHE_DIR"/$branch-$arch.lst
+ else
+ printf "No update found\n\n"
+ rm -f $tmpfile
+ fi
+ done
+done