<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.alpinelinux.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mcrute</id>
	<title>Alpine Linux - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.alpinelinux.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mcrute"/>
	<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/wiki/Special:Contributions/Mcrute"/>
	<updated>2026-04-25T22:40:34Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Release_Notes_for_Alpine_3.22.0&amp;diff=29859</id>
		<title>Release Notes for Alpine 3.22.0</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Release_Notes_for_Alpine_3.22.0&amp;diff=29859"/>
		<updated>2025-05-12T15:20:34Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As always, make sure to read [[Upgrading Alpine to a new major release]] when upgrading to a new release.&lt;br /&gt;
&lt;br /&gt;
If you experience any issues with the upgrade, please let us know and file an issue in our repositories.&lt;br /&gt;
&lt;br /&gt;
== Important changes ==&lt;br /&gt;
&lt;br /&gt;
== Significant changes ==&lt;br /&gt;
&lt;br /&gt;
=== apk-tools ===&lt;br /&gt;
&lt;br /&gt;
This release is the last release using apk-tools v2.14. The next Alpine v3.23 will include apk-tools v3. The packages and index format are still using the legacy v2 format.&lt;br /&gt;
&lt;br /&gt;
There are a number of new changes in the new apk-tools release. To test apk-tools v3, [https://wiki.alpinelinux.org/wiki/Upgrading_Alpine_Linux_to_a_new_release_branch#Upgrading_to_Edge upgrade to Alpine edge, enable the testing repository] and install {{pkg|apk-tools3}}.&lt;br /&gt;
&lt;br /&gt;
{{Note|TODO: if edge upgrades to apk-tools 3, remove the testing repo and apk-tools3 package mention}}&lt;br /&gt;
&lt;br /&gt;
=== KDE Plasma ===&lt;br /&gt;
&lt;br /&gt;
The X11 session for KDE Plasma has been removed. If you had {{pkg|plasma-workspace-x11|branch=v3.21|arch=}} installed make sure to remove it from {{path|/etc/apk/world}}. Wayland is the only available option now.&lt;br /&gt;
&lt;br /&gt;
=== SDL ===&lt;br /&gt;
&lt;br /&gt;
{{pkg|sdl3}} and {{pkg|sdl2-compat}} were moved to the community repository and are now the default SDL provider. To force the installation of {{pkg|sdl2}}, use &amp;lt;code&amp;gt;apk add sdl2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Adwaita Fonts ===&lt;br /&gt;
&lt;br /&gt;
As a result of [https://release.gnome.org/48/#new-fonts GNOME&#039;s switch] to {{pkg|adwaita-fonts}}, the default font for GTK-based applications (e.g. {{pkg|vte3}} or {{pkg|libadwaita}} Applications) was changed. If you want to revert or override the fonts, you can use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ apk add font-cantarell font-adobe-source-code-pro&lt;br /&gt;
$ gsettings set org.gnome.desktop.interface font-name &#039;Cantarell 11&#039;&lt;br /&gt;
$ gsettings set org.gnome.desktop.interface monospace-font-name &#039;Source Code Pro 11&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{pkg|adwaita-fonts}} is pulled in as a dependency of some packages since it broke the default behaviour for various applications.&lt;br /&gt;
&lt;br /&gt;
=== GeoClue ===&lt;br /&gt;
&lt;br /&gt;
Since Mozilla Location Services (MLS), which were used as the geolocation service in geoclue, [https://discourse.mozilla.org/t/retiring-the-mozilla-location-service/128693 has been retired by Mozilla], Alpine switched to [https://beacondb.net/ beaconDB] as the default geolocation provider. {{MR|76764}}&lt;br /&gt;
&lt;br /&gt;
=== BIRD Routing Daemon ===&lt;br /&gt;
&lt;br /&gt;
The {{pkg|bird|repo=community}} routing daemon package has been upgrade to version 3 which introduces a new multi-threaded architecture. A side effect of this change is [https://trubka.network.cz/pipermail/bird-users/2024-December/017973.html significantly increased memory consumption] of the daemon. This update is configuration-compatible with BIRD v2 but there are some behavioral backwards incompatibilities. Users should read the [https://gitlab.nic.cz/labs/bird/-/blob/stable-v3.0/doc/migration-bird3.md migration guide]. Notably the format of &amp;lt;tt&amp;gt;show route all&amp;lt;/tt&amp;gt; has changed as has the format of the logs, which may impact scripts and automation that consume those outputs. Users who require BIRD v2 should install the {{pkg|bird2|repo=community}} package instead.&lt;br /&gt;
&lt;br /&gt;
== Note-worthy updates ==&lt;br /&gt;
&lt;br /&gt;
As always, many packages were upgraded. Make sure to read the individual release notes of the projects you use.&lt;br /&gt;
&lt;br /&gt;
* Linux TODO&lt;br /&gt;
* busybox TODO&lt;br /&gt;
* GCC TODO&lt;br /&gt;
* LLVM TODO&lt;br /&gt;
* Go TODO&lt;br /&gt;
* Rust TODO&lt;br /&gt;
* PHP TODO&lt;br /&gt;
* GNOME TODO&lt;br /&gt;
* KDE Plasma TODO&lt;br /&gt;
* LXQt TODO&lt;br /&gt;
* Qt TODO&lt;br /&gt;
* wlroots TODO&lt;br /&gt;
* ISC BIND 9.20.TODO&lt;br /&gt;
* BIRD 3.1.TODO&lt;br /&gt;
&lt;br /&gt;
=== LLVM ===&lt;br /&gt;
&lt;br /&gt;
LLVM 20 is available as {{pkg|llvm}}/{{pkg|clang}} (or {{pkg|llvm20}}/{{pkg|clang20}} explictly) additionally to LLVM 19, 18, 17, 16 and 15. ({{MR|80901}}, {{MR|82502}})&lt;br /&gt;
&lt;br /&gt;
LLD is now also splitted per version and is available as {{pkg|lld20}} (default for {{pkg|lld}}), {{pkg|lld19}} and {{pkg|lld18}}. ({{MR|81774}})&lt;br /&gt;
&lt;br /&gt;
== Significant removals ==&lt;br /&gt;
&lt;br /&gt;
=== LXD ===&lt;br /&gt;
&lt;br /&gt;
LXD was moved to the testing repository and is therefore not available on Alpine Linux 3.22. It was deprecated in favor of {{pkg|incus}} and {{pkg|incus-feature}} (feature branch).&lt;br /&gt;
&lt;br /&gt;
Take a look at the [https://linuxcontainers.org/incus/docs/main/howto/server_migrate_lxd/ Migration Guide] on how to migrate from LXD to Incus using the {{pkg|incus-conversion}} or {{pkg|incus-feature-conversion}} package.&lt;br /&gt;
&lt;br /&gt;
=== Qt 5 ===&lt;br /&gt;
&lt;br /&gt;
On 26th of May 2025, Qt 5 will be unmaintained upstream. Therefore we&#039;re removing unused libraries from our repositories and are migrating the remaining packages to Qt 6.&lt;br /&gt;
&lt;br /&gt;
Applications that still use Qt 5 libraries won&#039;t be removed, but libraries without consumers in our repository will.&lt;br /&gt;
&lt;br /&gt;
For more information, see Issue {{Issue|17114}}.&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Release_Notes_for_Alpine_3.22.0&amp;diff=29858</id>
		<title>Release Notes for Alpine 3.22.0</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Release_Notes_for_Alpine_3.22.0&amp;diff=29858"/>
		<updated>2025-05-12T15:19:03Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As always, make sure to read [[Upgrading Alpine to a new major release]] when upgrading to a new release.&lt;br /&gt;
&lt;br /&gt;
If you experience any issues with the upgrade, please let us know and file an issue in our repositories.&lt;br /&gt;
&lt;br /&gt;
== Important changes ==&lt;br /&gt;
&lt;br /&gt;
== Significant changes ==&lt;br /&gt;
&lt;br /&gt;
=== apk-tools ===&lt;br /&gt;
&lt;br /&gt;
This release is the last release using apk-tools v2.14. The next Alpine v3.23 will include apk-tools v3. The packages and index format are still using the legacy v2 format.&lt;br /&gt;
&lt;br /&gt;
There are a number of new changes in the new apk-tools release. To test apk-tools v3, [https://wiki.alpinelinux.org/wiki/Upgrading_Alpine_Linux_to_a_new_release_branch#Upgrading_to_Edge upgrade to Alpine edge, enable the testing repository] and install {{pkg|apk-tools3}}.&lt;br /&gt;
&lt;br /&gt;
{{Note|TODO: if edge upgrades to apk-tools 3, remove the testing repo and apk-tools3 package mention}}&lt;br /&gt;
&lt;br /&gt;
=== KDE Plasma ===&lt;br /&gt;
&lt;br /&gt;
The X11 session for KDE Plasma has been removed. If you had {{pkg|plasma-workspace-x11|branch=v3.21|arch=}} installed make sure to remove it from {{path|/etc/apk/world}}. Wayland is the only available option now.&lt;br /&gt;
&lt;br /&gt;
=== SDL ===&lt;br /&gt;
&lt;br /&gt;
{{pkg|sdl3}} and {{pkg|sdl2-compat}} were moved to the community repository and are now the default SDL provider. To force the installation of {{pkg|sdl2}}, use &amp;lt;code&amp;gt;apk add sdl2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Adwaita Fonts ===&lt;br /&gt;
&lt;br /&gt;
As a result of [https://release.gnome.org/48/#new-fonts GNOME&#039;s switch] to {{pkg|adwaita-fonts}}, the default font for GTK-based applications (e.g. {{pkg|vte3}} or {{pkg|libadwaita}} Applications) was changed. If you want to revert or override the fonts, you can use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ apk add font-cantarell font-adobe-source-code-pro&lt;br /&gt;
$ gsettings set org.gnome.desktop.interface font-name &#039;Cantarell 11&#039;&lt;br /&gt;
$ gsettings set org.gnome.desktop.interface monospace-font-name &#039;Source Code Pro 11&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{pkg|adwaita-fonts}} is pulled in as a dependency of some packages since it broke the default behaviour for various applications.&lt;br /&gt;
&lt;br /&gt;
=== GeoClue ===&lt;br /&gt;
&lt;br /&gt;
Since Mozilla Location Services (MLS), which were used as the geolocation service in geoclue, [https://discourse.mozilla.org/t/retiring-the-mozilla-location-service/128693 has been retired by Mozilla], Alpine switched to [https://beacondb.net/ beaconDB] as the default geolocation provider. {{MR|76764}}&lt;br /&gt;
&lt;br /&gt;
=== BIRD Routing Daemon ===&lt;br /&gt;
&lt;br /&gt;
The {{pkg|bird|repo=community}} routing daemon package has been upgrade to version 3 which introduces a new multi-threaded architecture. A side effect of this change is [https://trubka.network.cz/pipermail/bird-users/2024-December/017973.html significantly increased memory consumption] of the daemon. This update is configuration-compatible with BIRD v2 but there are some behavioral backwards incompatibilities. Users should read the [https://gitlab.nic.cz/labs/bird/-/blob/stable-v3.0/doc/migration-bird3.md migration guide]. Notably the format of &amp;lt;tt&amp;gt;show route all&amp;lt;/tt&amp;gt; has changed as has the format of the logs, which may impact scripts and automation that consume those outputs. Users who require BIRD v2 should install the community/bird2 package instead.&lt;br /&gt;
&lt;br /&gt;
== Note-worthy updates ==&lt;br /&gt;
&lt;br /&gt;
As always, many packages were upgraded. Make sure to read the individual release notes of the projects you use.&lt;br /&gt;
&lt;br /&gt;
* Linux TODO&lt;br /&gt;
* busybox TODO&lt;br /&gt;
* GCC TODO&lt;br /&gt;
* LLVM TODO&lt;br /&gt;
* Go TODO&lt;br /&gt;
* Rust TODO&lt;br /&gt;
* PHP TODO&lt;br /&gt;
* GNOME TODO&lt;br /&gt;
* KDE Plasma TODO&lt;br /&gt;
* LXQt TODO&lt;br /&gt;
* Qt TODO&lt;br /&gt;
* wlroots TODO&lt;br /&gt;
* ISC BIND 9.20.TODO&lt;br /&gt;
* BIRD 3.1.TODO&lt;br /&gt;
&lt;br /&gt;
=== LLVM ===&lt;br /&gt;
&lt;br /&gt;
LLVM 20 is available as {{pkg|llvm}}/{{pkg|clang}} (or {{pkg|llvm20}}/{{pkg|clang20}} explictly) additionally to LLVM 19, 18, 17, 16 and 15. ({{MR|80901}}, {{MR|82502}})&lt;br /&gt;
&lt;br /&gt;
LLD is now also splitted per version and is available as {{pkg|lld20}} (default for {{pkg|lld}}), {{pkg|lld19}} and {{pkg|lld18}}. ({{MR|81774}})&lt;br /&gt;
&lt;br /&gt;
== Significant removals ==&lt;br /&gt;
&lt;br /&gt;
=== LXD ===&lt;br /&gt;
&lt;br /&gt;
LXD was moved to the testing repository and is therefore not available on Alpine Linux 3.22. It was deprecated in favor of {{pkg|incus}} and {{pkg|incus-feature}} (feature branch).&lt;br /&gt;
&lt;br /&gt;
Take a look at the [https://linuxcontainers.org/incus/docs/main/howto/server_migrate_lxd/ Migration Guide] on how to migrate from LXD to Incus using the {{pkg|incus-conversion}} or {{pkg|incus-feature-conversion}} package.&lt;br /&gt;
&lt;br /&gt;
=== Qt 5 ===&lt;br /&gt;
&lt;br /&gt;
On 26th of May 2025, Qt 5 will be unmaintained upstream. Therefore we&#039;re removing unused libraries from our repositories and are migrating the remaining packages to Qt 6.&lt;br /&gt;
&lt;br /&gt;
Applications that still use Qt 5 libraries won&#039;t be removed, but libraries without consumers in our repository will.&lt;br /&gt;
&lt;br /&gt;
For more information, see Issue {{Issue|17114}}.&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Release_Notes_for_Alpine_3.22.0&amp;diff=29857</id>
		<title>Release Notes for Alpine 3.22.0</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Release_Notes_for_Alpine_3.22.0&amp;diff=29857"/>
		<updated>2025-05-12T15:15:06Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: /* Significant changes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As always, make sure to read [[Upgrading Alpine to a new major release]] when upgrading to a new release.&lt;br /&gt;
&lt;br /&gt;
If you experience any issues with the upgrade, please let us know and file an issue in our repositories.&lt;br /&gt;
&lt;br /&gt;
== Important changes ==&lt;br /&gt;
&lt;br /&gt;
== Significant changes ==&lt;br /&gt;
&lt;br /&gt;
=== apk-tools ===&lt;br /&gt;
&lt;br /&gt;
This release is the last release using apk-tools v2.14. The next Alpine v3.23 will include apk-tools v3. The packages and index format are still using the legacy v2 format.&lt;br /&gt;
&lt;br /&gt;
There are a number of new changes in the new apk-tools release. To test apk-tools v3, [https://wiki.alpinelinux.org/wiki/Upgrading_Alpine_Linux_to_a_new_release_branch#Upgrading_to_Edge upgrade to Alpine edge, enable the testing repository] and install {{pkg|apk-tools3}}.&lt;br /&gt;
&lt;br /&gt;
{{Note|TODO: if edge upgrades to apk-tools 3, remove the testing repo and apk-tools3 package mention}}&lt;br /&gt;
&lt;br /&gt;
=== KDE Plasma ===&lt;br /&gt;
&lt;br /&gt;
The X11 session for KDE Plasma has been removed. If you had {{pkg|plasma-workspace-x11|branch=v3.21|arch=}} installed make sure to remove it from {{path|/etc/apk/world}}. Wayland is the only available option now.&lt;br /&gt;
&lt;br /&gt;
=== SDL ===&lt;br /&gt;
&lt;br /&gt;
{{pkg|sdl3}} and {{pkg|sdl2-compat}} were moved to the community repository and are now the default SDL provider. To force the installation of {{pkg|sdl2}}, use &amp;lt;code&amp;gt;apk add sdl2&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Adwaita Fonts ===&lt;br /&gt;
&lt;br /&gt;
As a result of [https://release.gnome.org/48/#new-fonts GNOME&#039;s switch] to {{pkg|adwaita-fonts}}, the default font for GTK-based applications (e.g. {{pkg|vte3}} or {{pkg|libadwaita}} Applications) was changed. If you want to revert or override the fonts, you can use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ apk add font-cantarell font-adobe-source-code-pro&lt;br /&gt;
$ gsettings set org.gnome.desktop.interface font-name &#039;Cantarell 11&#039;&lt;br /&gt;
$ gsettings set org.gnome.desktop.interface monospace-font-name &#039;Source Code Pro 11&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{pkg|adwaita-fonts}} is pulled in as a dependency of some packages since it broke the default behaviour for various applications.&lt;br /&gt;
&lt;br /&gt;
=== GeoClue ===&lt;br /&gt;
&lt;br /&gt;
Since Mozilla Location Services (MLS), which were used as the geolocation service in geoclue, [https://discourse.mozilla.org/t/retiring-the-mozilla-location-service/128693 has been retired by Mozilla], Alpine switched to [https://beacondb.net/ beaconDB] as the default geolocation provider. {{MR|76764}}&lt;br /&gt;
&lt;br /&gt;
=== BIRD Routing Daemon ===&lt;br /&gt;
&lt;br /&gt;
The BIRD routing daemon has been upgrade to version 3 which introduces a new multi-threaded architecture. A side effect of this change is [https://trubka.network.cz/pipermail/bird-users/2024-December/017973.html significantly increased memory consumption] of the daemon. This update is configuration-compatible with BIRD v2 but there are some behavioral backwards incompatibilities. Users should read the [https://gitlab.nic.cz/labs/bird/-/blob/stable-v3.0/doc/migration-bird3.md migration guide]. Notably the format of `show route all` has changed as has the format of the logs. Users who require BIRD v2 should install the community/bird2 package instead.&lt;br /&gt;
&lt;br /&gt;
== Note-worthy updates ==&lt;br /&gt;
&lt;br /&gt;
As always, many packages were upgraded. Make sure to read the individual release notes of the projects you use.&lt;br /&gt;
&lt;br /&gt;
* Linux TODO&lt;br /&gt;
* busybox TODO&lt;br /&gt;
* GCC TODO&lt;br /&gt;
* LLVM TODO&lt;br /&gt;
* Go TODO&lt;br /&gt;
* Rust TODO&lt;br /&gt;
* PHP TODO&lt;br /&gt;
* GNOME TODO&lt;br /&gt;
* KDE Plasma TODO&lt;br /&gt;
* LXQt TODO&lt;br /&gt;
* Qt TODO&lt;br /&gt;
* wlroots TODO&lt;br /&gt;
* ISC BIND 9.20.TODO&lt;br /&gt;
&lt;br /&gt;
=== LLVM ===&lt;br /&gt;
&lt;br /&gt;
LLVM 20 is available as {{pkg|llvm}}/{{pkg|clang}} (or {{pkg|llvm20}}/{{pkg|clang20}} explictly) additionally to LLVM 19, 18, 17, 16 and 15. ({{MR|80901}}, {{MR|82502}})&lt;br /&gt;
&lt;br /&gt;
LLD is now also splitted per version and is available as {{pkg|lld20}} (default for {{pkg|lld}}), {{pkg|lld19}} and {{pkg|lld18}}. ({{MR|81774}})&lt;br /&gt;
&lt;br /&gt;
== Significant removals ==&lt;br /&gt;
&lt;br /&gt;
=== LXD ===&lt;br /&gt;
&lt;br /&gt;
LXD was moved to the testing repository and is therefore not available on Alpine Linux 3.22. It was deprecated in favor of {{pkg|incus}} and {{pkg|incus-feature}} (feature branch).&lt;br /&gt;
&lt;br /&gt;
Take a look at the [https://linuxcontainers.org/incus/docs/main/howto/server_migrate_lxd/ Migration Guide] on how to migrate from LXD to Incus using the {{pkg|incus-conversion}} or {{pkg|incus-feature-conversion}} package.&lt;br /&gt;
&lt;br /&gt;
=== Qt 5 ===&lt;br /&gt;
&lt;br /&gt;
On 26th of May 2025, Qt 5 will be unmaintained upstream. Therefore we&#039;re removing unused libraries from our repositories and are migrating the remaining packages to Qt 6.&lt;br /&gt;
&lt;br /&gt;
Applications that still use Qt 5 libraries won&#039;t be removed, but libraries without consumers in our repository will.&lt;br /&gt;
&lt;br /&gt;
For more information, see Issue {{Issue|17114}}.&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=How_to_setup_a_Alpine_Linux_mirror&amp;diff=22912</id>
		<title>How to setup a Alpine Linux mirror</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=How_to_setup_a_Alpine_Linux_mirror&amp;diff=22912"/>
		<updated>2023-01-13T18:14:58Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This document describes how to set up an Alpine Linux mirror and make it available via http and rsync.&lt;br /&gt;
&lt;br /&gt;
We will:&lt;br /&gt;
* create the dir where we have the mirror&lt;br /&gt;
* set up a cron job to sync with master mirror every hour&lt;br /&gt;
* set up lighttpd for http access&lt;br /&gt;
* set up rsync so other mirrors can rsync from you&lt;br /&gt;
&lt;br /&gt;
Make sure that you have enough disk space.&lt;br /&gt;
&lt;br /&gt;
Current (2023-01-13) disk usage in GB:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!edge&lt;br /&gt;
!v3.0&lt;br /&gt;
!v3.1&lt;br /&gt;
!v3.2&lt;br /&gt;
!v3.3&lt;br /&gt;
!v3.4&lt;br /&gt;
!v3.5&lt;br /&gt;
!v3.6&lt;br /&gt;
!v3.7&lt;br /&gt;
!v3.8&lt;br /&gt;
!v3.9&lt;br /&gt;
!v3.10&lt;br /&gt;
!v3.11&lt;br /&gt;
!v3.12&lt;br /&gt;
!v3.13&lt;br /&gt;
!v3.14&lt;br /&gt;
!v3.15&lt;br /&gt;
!v3.16&lt;br /&gt;
!v3.17&lt;br /&gt;
&lt;br /&gt;
!total&lt;br /&gt;
|-&lt;br /&gt;
|349&lt;br /&gt;
|17&lt;br /&gt;
|18&lt;br /&gt;
|15&lt;br /&gt;
|21&lt;br /&gt;
|25&lt;br /&gt;
|27&lt;br /&gt;
|45&lt;br /&gt;
|43&lt;br /&gt;
|60&lt;br /&gt;
|73&lt;br /&gt;
|92&lt;br /&gt;
|126&lt;br /&gt;
|148&lt;br /&gt;
|156&lt;br /&gt;
|174&lt;br /&gt;
|176&lt;br /&gt;
|184&lt;br /&gt;
|211&lt;br /&gt;
&lt;br /&gt;
|&#039;&#039;&#039;1960&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Script used to calculate the size:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
total=0&lt;br /&gt;
dest=&amp;quot;$(mktemp -d)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for dir in edge v3.0 v3.1 v3.2 v3.3 v3.4 v3.5 v3.6 v3.7 v3.8 v3.9 v3.10 v3.11 v3.12 v3.13 v3.14 v3.15 v3.16; do&lt;br /&gt;
    old_total=&amp;quot;$total&amp;quot;&lt;br /&gt;
    src=&amp;quot;rsync://rsync.alpinelinux.org/alpine/$dir/&amp;quot;&lt;br /&gt;
    size=`rsync -a -n --stats &amp;quot;$src&amp;quot; &amp;quot;$dest&amp;quot; | grep &#039;^Total file size&#039; | tr -d &#039;,&#039; | awk &#039;{ print $4 }&#039;`&lt;br /&gt;
    total=$(( $old_total + $size ))&lt;br /&gt;
    echo &amp;quot;$dir: $size&amp;quot; | awk &#039;{ print $1 sprintf(&amp;quot;%.1f&amp;quot;, $2/1073741824) }&#039;&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;total: $total&amp;quot; | awk &#039;{ print $1 sprintf(&amp;quot;%.1f&amp;quot;, $2/1073741824) }&#039;&lt;br /&gt;
rm -r &amp;quot;$dest&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Setting up the cron job ==&lt;br /&gt;
Install rsync which will be used to sync from the master mirror.&lt;br /&gt;
{{Cmd|apk add rsync}}&lt;br /&gt;
&lt;br /&gt;
Save the following file as &#039;&#039;/etc/periodic/hourly/alpine-mirror&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env sh&lt;br /&gt;
&lt;br /&gt;
# make sure we never run 2 rsync at the same time&lt;br /&gt;
lockfile=&amp;quot;/tmp/alpine-mirror.lock&amp;quot;&lt;br /&gt;
if [ -z &amp;quot;$flock&amp;quot; ] ; then&lt;br /&gt;
  exec env flock=1 flock -n $lockfile &amp;quot;$0&amp;quot; &amp;quot;$@&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
src=rsync://rsync.alpinelinux.org/alpine/ &lt;br /&gt;
dest=/var/www/localhost/htdocs/alpine/&lt;br /&gt;
&lt;br /&gt;
# uncomment this to exclude old v2.x branches&lt;br /&gt;
#exclude=&amp;quot;--exclude v2.*&amp;quot;&lt;br /&gt;
&lt;br /&gt;
mkdir -p &amp;quot;$dest&amp;quot;&lt;br /&gt;
/usr/bin/rsync \&lt;br /&gt;
        --archive \&lt;br /&gt;
        --update \&lt;br /&gt;
        --hard-links \&lt;br /&gt;
        --delete \&lt;br /&gt;
        --delete-after \&lt;br /&gt;
        --delay-updates \&lt;br /&gt;
        --timeout=600 \&lt;br /&gt;
        $exclude \&lt;br /&gt;
        &amp;quot;$src&amp;quot; &amp;quot;$dest&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(or use [https://gist.github.com/jirutka/288c6fff7c0b8a835d143686207316be this script])&lt;br /&gt;
&lt;br /&gt;
Make it executable:&lt;br /&gt;
{{Cmd|&amp;lt;nowiki&amp;gt;chmod +x /etc/periodic/hourly/alpine-mirror&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
Now it will sync every hour. (given cron runs)&lt;br /&gt;
&lt;br /&gt;
== Setting up HTTP access via lighttpd ==&lt;br /&gt;
&lt;br /&gt;
Install the lighttpd server&lt;br /&gt;
{{Cmd|apk add lighttpd}}&lt;br /&gt;
&lt;br /&gt;
Enable dir listings by uncommenting the following line in &#039;&#039;/etc/lighttpd/lighttpd.conf&#039;&#039;:&lt;br /&gt;
 dir-listing.activate      = &amp;quot;enable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Also set cache-control to force cache revalidate every 30 mins. Uncomment mod_setenv in &#039;&#039;/etc/lighttpd/lighttpd.conf&#039;&#039;:&lt;br /&gt;
 &amp;quot;mod_setenv&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
Add also the following lines to &#039;&#039;/etc/lighttpd/lighttpd.conf&#039;&#039;:&lt;br /&gt;
 setenv.add-response-header += (           &lt;br /&gt;
         &amp;quot;Cache-Control&amp;quot; =&amp;gt; &amp;quot;must-revalidate&amp;quot;&lt;br /&gt;
 )&lt;br /&gt;
&lt;br /&gt;
Start lighttpd and make it start at boot:&lt;br /&gt;
{{Cmd|rc-service lighttpd start&lt;br /&gt;
rc-update add lighttpd}}&lt;br /&gt;
&lt;br /&gt;
{{Note|You may wish to consider [[Darkhttpd]] as an alternative to [[Lighttpd]]&lt;br /&gt;
&lt;br /&gt;
If so, simply install, start and auto-start the webserver:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|apk add darkhttpd &amp;amp;&amp;amp; rc-service darkhttpd start &amp;amp;&amp;amp; rc-update add darkhttpd}}&lt;br /&gt;
&lt;br /&gt;
Darkhttpd will, by default, offer directory listings and serve data from /var/www/localhost/htdocs/ &lt;br /&gt;
&lt;br /&gt;
See the main article on [[Darkhttpd]] for more configuration options}}&lt;br /&gt;
&lt;br /&gt;
== Setting up rsyncd ==&lt;br /&gt;
Add the following lines to &#039;&#039;/etc/rsyncd.conf&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[alpine]&lt;br /&gt;
        path = /var/www/localhost/htdocs/alpine&lt;br /&gt;
        comment = My Alpine Linux Mirror&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optionally set a bandwidth limit in &#039;&#039;/etc/conf.d/rsyncd&#039;&#039;. In this example we limit to 500Kbytes/s (approx 5Mbit/s)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSYNC_OPTS=&amp;quot;--bwlimit=500&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mirror statistics ==&lt;br /&gt;
&lt;br /&gt;
Simple bandwidth statistics can be generated with vnstat.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|apk add vnstat}}&lt;br /&gt;
&lt;br /&gt;
edit /etc/vnstat.conf and replace the interface name with the appropriate one.&lt;br /&gt;
&lt;br /&gt;
Start vnstatd&lt;br /&gt;
&lt;br /&gt;
{{Cmd|/etc/init.d/vnstatd start }}&lt;br /&gt;
&lt;br /&gt;
copy the following script to /etc/periodic/15min/stats and make sure your crond is running.&lt;br /&gt;
please not that heredoc should be tab indented or the script will fail. A working copy can be found here: http://tpaste.us/RrMv&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env sh&lt;br /&gt;
&lt;br /&gt;
output=&amp;quot;/var/www/localhost/htdocs/.stats&amp;quot;&lt;br /&gt;
nic=&amp;quot;eth0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
generate_index() {&lt;br /&gt;
    cat &amp;lt;&amp;lt;-EOF&lt;br /&gt;
    &amp;lt;!doctype html&amp;gt;&lt;br /&gt;
    &amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;head&amp;gt;&lt;br /&gt;
        &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;meta http-equiv=&amp;quot;cache-control&amp;quot; content=no-cache&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;meta http-equiv=&amp;quot;refresh&amp;quot; content=&amp;quot;3000&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;title&amp;gt;Alpine Linux mirror statistics&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;/head&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        &amp;lt;table border=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;summary.png&amp;quot; alt=&amp;quot;summary&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;hours.png&amp;quot; alt=&amp;quot;hours&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
            &amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;2&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;days.png&amp;quot; alt=&amp;quot;days&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;top10.png&amp;quot; alt=&amp;quot;top10&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;months.png&amp;quot; alt=&amp;quot;months&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
        &amp;lt;/table&amp;gt;&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
    &amp;lt;/html&amp;gt;&lt;br /&gt;
    EOF&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if  [ ! -f &amp;quot;$output&amp;quot;/index.html ]; then&lt;br /&gt;
    mkdir -p $output&lt;br /&gt;
    generate_index &amp;gt; &amp;quot;$output&amp;quot;/index.html&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
for type in hours days months top10 summary hsummary vsummary; do&lt;br /&gt;
    vnstati --${type} -i $nic -o $output/${type}.png&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Update mirror from mqtt ==&lt;br /&gt;
&lt;br /&gt;
If you want your mirror to be really uptodate compared to our master mirror you can subscribe to Alpine Linux message server &amp;quot;msg.alpinelinux.org&amp;quot; and check for upload messages.&lt;br /&gt;
Add mqtt-exec to be able to execute processes when specific topics are being send.&lt;br /&gt;
&lt;br /&gt;
{{Cmd| apk add mqtt-exec}}&lt;br /&gt;
&lt;br /&gt;
mqtt-exec supports running multiple time so we need to setup a specific config.&lt;br /&gt;
&lt;br /&gt;
{{Cmd| ln -s /etc/init.d/mqtt-exec /etc/init.d/mqtt-exec.sync-mirror}}&lt;br /&gt;
&lt;br /&gt;
{{Cmd| ln -s /etc/conf.d/mqtt-exec /etc/conf.d/mqtt-exec.sync-mirror}}&lt;br /&gt;
&lt;br /&gt;
edit /etc/conf.d/mqtt-exec.sync-mirror&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mqtt_topics=&amp;quot;rsync/rsync.alpinelinux.org/#&amp;quot;&lt;br /&gt;
exec_user=&amp;quot;buildozer&amp;quot;&lt;br /&gt;
exec_command=&amp;quot;/usr/local/bin/sync-mirror&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Copy the following file to /usr/local/bin/sync-mirror and make it executable (dont forget to update the variables).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
src=&amp;quot;rsync://rsync.alpinelinux.org/alpine/&amp;quot;&lt;br /&gt;
dest=&amp;quot;/var/www/localhost/htdocs/alpine/&amp;quot;&lt;br /&gt;
lock=&amp;quot;/tmp/sync-mirror.lock&amp;quot;&lt;br /&gt;
topic=&amp;quot;$1&amp;quot;&lt;br /&gt;
dir=&amp;quot;$2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[ -z &amp;quot;$flock&amp;quot; ] &amp;amp;&amp;amp; exec env flock=1 flock $lock $0 &amp;quot;$@&amp;quot;&lt;br /&gt;
&lt;br /&gt;
if [ -n &amp;quot;$dir&amp;quot; ] &amp;amp;&amp;amp; [ -d &amp;quot;$dest/${dir%/*}&amp;quot; ]; then&lt;br /&gt;
    logger &amp;quot;Syncing directory: $dir&amp;quot;&lt;br /&gt;
    src=&amp;quot;${src}${dir%/}/&amp;quot;&lt;br /&gt;
    dest=&amp;quot;${dest}${dir%/}/&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
    logger &amp;quot;Syncing all directories&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
/usr/bin/rsync \&lt;br /&gt;
    --archive \&lt;br /&gt;
    --update \&lt;br /&gt;
    --verbose \&lt;br /&gt;
    --progress \&lt;br /&gt;
    --timeout=600 \&lt;br /&gt;
    --delay-updates \&lt;br /&gt;
    --delete-after \&lt;br /&gt;
    &amp;quot;$src&amp;quot; \&lt;br /&gt;
    &amp;quot;$dest&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And finally start mqtt-exec and let it listen on msg.alpinelinux.org&lt;br /&gt;
&lt;br /&gt;
{{Cmd|/etc/init.d/mqtt-exec.sync-mirror start}}&lt;br /&gt;
&lt;br /&gt;
To make sure you are not missing any packages (in case something goes wrong with MQTT subscription) you can periodically sync all directories by adding the script to cron.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|ln -s /usr/local/bin/sync-mirror /etc/periodic/hourly/sync-mirror}}&lt;br /&gt;
&lt;br /&gt;
Now watch your syslog as it should tell you when it will update directories in your local mirror.&lt;br /&gt;
&lt;br /&gt;
== Partial mirror using nginx ==&lt;br /&gt;
&lt;br /&gt;
For a private mirror it might make sense to sync only the newest versions of Alpine to save space, but if you &#039;&#039;do&#039;&#039; point an old Alpine version to your mirror they should still be able to install packages. We can achieve this by using nginx to serve the mirrored content and use regex location matching to redirect requests to a public mirror.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume you chose to only mirror Alpine versions up from v3.13. If a client asks your mirror for v.3.10 it should redirect to another mirror.&lt;br /&gt;
&lt;br /&gt;
Your nginx config server block should look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
server {&lt;br /&gt;
        listen 80;&lt;br /&gt;
        server_name alpine.mydomain.local;&lt;br /&gt;
        root /data/alpine;          # point to where your alpine mirror is located. make sure nginx is allowed to read it&lt;br /&gt;
        autoindex on;               # Enable indexing&lt;br /&gt;
&lt;br /&gt;
        # the following location block will match for v3.0 to v3.12&lt;br /&gt;
        # and will forward it to dl-4.alpinelinux.org.&lt;br /&gt;
        location ~* /(v3\.([1-9]|1[012]))$&lt;br /&gt;
        {&lt;br /&gt;
          return 302 http://dl-cdn.alpinelinux.org/alpine$request_uri;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding sync script could look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env sh&lt;br /&gt;
&lt;br /&gt;
# make sure we never run 2 rsync at the same time&lt;br /&gt;
lockfile=&amp;quot;/tmp/alpine-mirror.lock&amp;quot;&lt;br /&gt;
if [ -z &amp;quot;$flock&amp;quot; ] ; then&lt;br /&gt;
  exec env flock=1 flock -n $lockfile &amp;quot;$0&amp;quot; &amp;quot;$@&amp;quot;&lt;br /&gt;
  fi&lt;br /&gt;
&lt;br /&gt;
  src=rsync://rsync.alpinelinux.org/alpine/&lt;br /&gt;
  dest=/data/alpine/&lt;br /&gt;
&lt;br /&gt;
  exclude=&amp;quot;--exclude v2.* --exclude v3.0 --exclude v3.1 --exclude v3.2 --exclude v3.3 --exclude v3.4 --exclude v3.5 --exclude v3.6 --exclude v3.7 --exclude v3.8 --exclude v3.9 --exclude v3.10 --exclude v3.11 --exclude v3.12&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  mkdir -p &amp;quot;$dest&amp;quot;&lt;br /&gt;
  /usr/bin/rsync -vvv \&lt;br /&gt;
  --archive \&lt;br /&gt;
  --update \&lt;br /&gt;
  --hard-links \&lt;br /&gt;
  --delete \&lt;br /&gt;
  --delete-after \&lt;br /&gt;
  --delete-excluded \&lt;br /&gt;
  --delay-updates \&lt;br /&gt;
  --timeout=600 \&lt;br /&gt;
  $exclude \&lt;br /&gt;
  &amp;quot;$src&amp;quot; &amp;quot;$dest&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Package Manager]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=How_to_setup_a_Alpine_Linux_mirror&amp;diff=22911</id>
		<title>How to setup a Alpine Linux mirror</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=How_to_setup_a_Alpine_Linux_mirror&amp;diff=22911"/>
		<updated>2023-01-13T18:14:19Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: Update mirror sizes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This document describes how to set up an Alpine Linux mirror and make it available via http and rsync.&lt;br /&gt;
&lt;br /&gt;
We will:&lt;br /&gt;
* create the dir where we have the mirror&lt;br /&gt;
* set up a cron job to sync with master mirror every hour&lt;br /&gt;
* set up lighttpd for http access&lt;br /&gt;
* set up rsync so other mirrors can rsync from you&lt;br /&gt;
&lt;br /&gt;
Make sure that you have enough disk space.&lt;br /&gt;
&lt;br /&gt;
Current (2023-01-13) disk usage in GB:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!edge&lt;br /&gt;
!v3.0&lt;br /&gt;
!v3.1&lt;br /&gt;
!v3.2&lt;br /&gt;
!v3.3&lt;br /&gt;
!v3.4&lt;br /&gt;
!v3.5&lt;br /&gt;
!v3.6&lt;br /&gt;
!v3.7&lt;br /&gt;
!v3.8&lt;br /&gt;
!v3.9&lt;br /&gt;
!v3.10&lt;br /&gt;
!v3.11&lt;br /&gt;
!v3.12&lt;br /&gt;
!v3.13&lt;br /&gt;
!v3.14&lt;br /&gt;
!v3.15&lt;br /&gt;
!v3.16&lt;br /&gt;
|v3.17&lt;br /&gt;
&lt;br /&gt;
!total&lt;br /&gt;
|-&lt;br /&gt;
|349&lt;br /&gt;
|17&lt;br /&gt;
|18&lt;br /&gt;
|15&lt;br /&gt;
|21&lt;br /&gt;
|25&lt;br /&gt;
|27&lt;br /&gt;
|45&lt;br /&gt;
|43&lt;br /&gt;
|60&lt;br /&gt;
|73&lt;br /&gt;
|92&lt;br /&gt;
|126&lt;br /&gt;
|148&lt;br /&gt;
|156&lt;br /&gt;
|174&lt;br /&gt;
|176&lt;br /&gt;
|184&lt;br /&gt;
|211&lt;br /&gt;
&lt;br /&gt;
|&#039;&#039;&#039;1960&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Script used to calculate the size:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
total=0&lt;br /&gt;
dest=&amp;quot;$(mktemp -d)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
for dir in edge v3.0 v3.1 v3.2 v3.3 v3.4 v3.5 v3.6 v3.7 v3.8 v3.9 v3.10 v3.11 v3.12 v3.13 v3.14 v3.15 v3.16; do&lt;br /&gt;
    old_total=&amp;quot;$total&amp;quot;&lt;br /&gt;
    src=&amp;quot;rsync://rsync.alpinelinux.org/alpine/$dir/&amp;quot;&lt;br /&gt;
    size=`rsync -a -n --stats &amp;quot;$src&amp;quot; &amp;quot;$dest&amp;quot; | grep &#039;^Total file size&#039; | tr -d &#039;,&#039; | awk &#039;{ print $4 }&#039;`&lt;br /&gt;
    total=$(( $old_total + $size ))&lt;br /&gt;
    echo &amp;quot;$dir: $size&amp;quot; | awk &#039;{ print $1 sprintf(&amp;quot;%.1f&amp;quot;, $2/1073741824) }&#039;&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;total: $total&amp;quot; | awk &#039;{ print $1 sprintf(&amp;quot;%.1f&amp;quot;, $2/1073741824) }&#039;&lt;br /&gt;
rm -r &amp;quot;$dest&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Setting up the cron job ==&lt;br /&gt;
Install rsync which will be used to sync from the master mirror.&lt;br /&gt;
{{Cmd|apk add rsync}}&lt;br /&gt;
&lt;br /&gt;
Save the following file as &#039;&#039;/etc/periodic/hourly/alpine-mirror&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env sh&lt;br /&gt;
&lt;br /&gt;
# make sure we never run 2 rsync at the same time&lt;br /&gt;
lockfile=&amp;quot;/tmp/alpine-mirror.lock&amp;quot;&lt;br /&gt;
if [ -z &amp;quot;$flock&amp;quot; ] ; then&lt;br /&gt;
  exec env flock=1 flock -n $lockfile &amp;quot;$0&amp;quot; &amp;quot;$@&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
src=rsync://rsync.alpinelinux.org/alpine/ &lt;br /&gt;
dest=/var/www/localhost/htdocs/alpine/&lt;br /&gt;
&lt;br /&gt;
# uncomment this to exclude old v2.x branches&lt;br /&gt;
#exclude=&amp;quot;--exclude v2.*&amp;quot;&lt;br /&gt;
&lt;br /&gt;
mkdir -p &amp;quot;$dest&amp;quot;&lt;br /&gt;
/usr/bin/rsync \&lt;br /&gt;
        --archive \&lt;br /&gt;
        --update \&lt;br /&gt;
        --hard-links \&lt;br /&gt;
        --delete \&lt;br /&gt;
        --delete-after \&lt;br /&gt;
        --delay-updates \&lt;br /&gt;
        --timeout=600 \&lt;br /&gt;
        $exclude \&lt;br /&gt;
        &amp;quot;$src&amp;quot; &amp;quot;$dest&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(or use [https://gist.github.com/jirutka/288c6fff7c0b8a835d143686207316be this script])&lt;br /&gt;
&lt;br /&gt;
Make it executable:&lt;br /&gt;
{{Cmd|&amp;lt;nowiki&amp;gt;chmod +x /etc/periodic/hourly/alpine-mirror&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
Now it will sync every hour. (given cron runs)&lt;br /&gt;
&lt;br /&gt;
== Setting up HTTP access via lighttpd ==&lt;br /&gt;
&lt;br /&gt;
Install the lighttpd server&lt;br /&gt;
{{Cmd|apk add lighttpd}}&lt;br /&gt;
&lt;br /&gt;
Enable dir listings by uncommenting the following line in &#039;&#039;/etc/lighttpd/lighttpd.conf&#039;&#039;:&lt;br /&gt;
 dir-listing.activate      = &amp;quot;enable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Also set cache-control to force cache revalidate every 30 mins. Uncomment mod_setenv in &#039;&#039;/etc/lighttpd/lighttpd.conf&#039;&#039;:&lt;br /&gt;
 &amp;quot;mod_setenv&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
Add also the following lines to &#039;&#039;/etc/lighttpd/lighttpd.conf&#039;&#039;:&lt;br /&gt;
 setenv.add-response-header += (           &lt;br /&gt;
         &amp;quot;Cache-Control&amp;quot; =&amp;gt; &amp;quot;must-revalidate&amp;quot;&lt;br /&gt;
 )&lt;br /&gt;
&lt;br /&gt;
Start lighttpd and make it start at boot:&lt;br /&gt;
{{Cmd|rc-service lighttpd start&lt;br /&gt;
rc-update add lighttpd}}&lt;br /&gt;
&lt;br /&gt;
{{Note|You may wish to consider [[Darkhttpd]] as an alternative to [[Lighttpd]]&lt;br /&gt;
&lt;br /&gt;
If so, simply install, start and auto-start the webserver:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|apk add darkhttpd &amp;amp;&amp;amp; rc-service darkhttpd start &amp;amp;&amp;amp; rc-update add darkhttpd}}&lt;br /&gt;
&lt;br /&gt;
Darkhttpd will, by default, offer directory listings and serve data from /var/www/localhost/htdocs/ &lt;br /&gt;
&lt;br /&gt;
See the main article on [[Darkhttpd]] for more configuration options}}&lt;br /&gt;
&lt;br /&gt;
== Setting up rsyncd ==&lt;br /&gt;
Add the following lines to &#039;&#039;/etc/rsyncd.conf&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[alpine]&lt;br /&gt;
        path = /var/www/localhost/htdocs/alpine&lt;br /&gt;
        comment = My Alpine Linux Mirror&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optionally set a bandwidth limit in &#039;&#039;/etc/conf.d/rsyncd&#039;&#039;. In this example we limit to 500Kbytes/s (approx 5Mbit/s)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSYNC_OPTS=&amp;quot;--bwlimit=500&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mirror statistics ==&lt;br /&gt;
&lt;br /&gt;
Simple bandwidth statistics can be generated with vnstat.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|apk add vnstat}}&lt;br /&gt;
&lt;br /&gt;
edit /etc/vnstat.conf and replace the interface name with the appropriate one.&lt;br /&gt;
&lt;br /&gt;
Start vnstatd&lt;br /&gt;
&lt;br /&gt;
{{Cmd|/etc/init.d/vnstatd start }}&lt;br /&gt;
&lt;br /&gt;
copy the following script to /etc/periodic/15min/stats and make sure your crond is running.&lt;br /&gt;
please not that heredoc should be tab indented or the script will fail. A working copy can be found here: http://tpaste.us/RrMv&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env sh&lt;br /&gt;
&lt;br /&gt;
output=&amp;quot;/var/www/localhost/htdocs/.stats&amp;quot;&lt;br /&gt;
nic=&amp;quot;eth0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
generate_index() {&lt;br /&gt;
    cat &amp;lt;&amp;lt;-EOF&lt;br /&gt;
    &amp;lt;!doctype html&amp;gt;&lt;br /&gt;
    &amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;head&amp;gt;&lt;br /&gt;
        &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;meta http-equiv=&amp;quot;cache-control&amp;quot; content=no-cache&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;meta http-equiv=&amp;quot;refresh&amp;quot; content=&amp;quot;3000&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;title&amp;gt;Alpine Linux mirror statistics&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;/head&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        &amp;lt;table border=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;summary.png&amp;quot; alt=&amp;quot;summary&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;hours.png&amp;quot; alt=&amp;quot;hours&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
            &amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;2&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;days.png&amp;quot; alt=&amp;quot;days&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;top10.png&amp;quot; alt=&amp;quot;top10&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;months.png&amp;quot; alt=&amp;quot;months&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
        &amp;lt;/table&amp;gt;&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
    &amp;lt;/html&amp;gt;&lt;br /&gt;
    EOF&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if  [ ! -f &amp;quot;$output&amp;quot;/index.html ]; then&lt;br /&gt;
    mkdir -p $output&lt;br /&gt;
    generate_index &amp;gt; &amp;quot;$output&amp;quot;/index.html&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
for type in hours days months top10 summary hsummary vsummary; do&lt;br /&gt;
    vnstati --${type} -i $nic -o $output/${type}.png&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Update mirror from mqtt ==&lt;br /&gt;
&lt;br /&gt;
If you want your mirror to be really uptodate compared to our master mirror you can subscribe to Alpine Linux message server &amp;quot;msg.alpinelinux.org&amp;quot; and check for upload messages.&lt;br /&gt;
Add mqtt-exec to be able to execute processes when specific topics are being send.&lt;br /&gt;
&lt;br /&gt;
{{Cmd| apk add mqtt-exec}}&lt;br /&gt;
&lt;br /&gt;
mqtt-exec supports running multiple time so we need to setup a specific config.&lt;br /&gt;
&lt;br /&gt;
{{Cmd| ln -s /etc/init.d/mqtt-exec /etc/init.d/mqtt-exec.sync-mirror}}&lt;br /&gt;
&lt;br /&gt;
{{Cmd| ln -s /etc/conf.d/mqtt-exec /etc/conf.d/mqtt-exec.sync-mirror}}&lt;br /&gt;
&lt;br /&gt;
edit /etc/conf.d/mqtt-exec.sync-mirror&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mqtt_topics=&amp;quot;rsync/rsync.alpinelinux.org/#&amp;quot;&lt;br /&gt;
exec_user=&amp;quot;buildozer&amp;quot;&lt;br /&gt;
exec_command=&amp;quot;/usr/local/bin/sync-mirror&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Copy the following file to /usr/local/bin/sync-mirror and make it executable (dont forget to update the variables).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
src=&amp;quot;rsync://rsync.alpinelinux.org/alpine/&amp;quot;&lt;br /&gt;
dest=&amp;quot;/var/www/localhost/htdocs/alpine/&amp;quot;&lt;br /&gt;
lock=&amp;quot;/tmp/sync-mirror.lock&amp;quot;&lt;br /&gt;
topic=&amp;quot;$1&amp;quot;&lt;br /&gt;
dir=&amp;quot;$2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[ -z &amp;quot;$flock&amp;quot; ] &amp;amp;&amp;amp; exec env flock=1 flock $lock $0 &amp;quot;$@&amp;quot;&lt;br /&gt;
&lt;br /&gt;
if [ -n &amp;quot;$dir&amp;quot; ] &amp;amp;&amp;amp; [ -d &amp;quot;$dest/${dir%/*}&amp;quot; ]; then&lt;br /&gt;
    logger &amp;quot;Syncing directory: $dir&amp;quot;&lt;br /&gt;
    src=&amp;quot;${src}${dir%/}/&amp;quot;&lt;br /&gt;
    dest=&amp;quot;${dest}${dir%/}/&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
    logger &amp;quot;Syncing all directories&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
/usr/bin/rsync \&lt;br /&gt;
    --archive \&lt;br /&gt;
    --update \&lt;br /&gt;
    --verbose \&lt;br /&gt;
    --progress \&lt;br /&gt;
    --timeout=600 \&lt;br /&gt;
    --delay-updates \&lt;br /&gt;
    --delete-after \&lt;br /&gt;
    &amp;quot;$src&amp;quot; \&lt;br /&gt;
    &amp;quot;$dest&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And finally start mqtt-exec and let it listen on msg.alpinelinux.org&lt;br /&gt;
&lt;br /&gt;
{{Cmd|/etc/init.d/mqtt-exec.sync-mirror start}}&lt;br /&gt;
&lt;br /&gt;
To make sure you are not missing any packages (in case something goes wrong with MQTT subscription) you can periodically sync all directories by adding the script to cron.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|ln -s /usr/local/bin/sync-mirror /etc/periodic/hourly/sync-mirror}}&lt;br /&gt;
&lt;br /&gt;
Now watch your syslog as it should tell you when it will update directories in your local mirror.&lt;br /&gt;
&lt;br /&gt;
== Partial mirror using nginx ==&lt;br /&gt;
&lt;br /&gt;
For a private mirror it might make sense to sync only the newest versions of Alpine to save space, but if you &#039;&#039;do&#039;&#039; point an old Alpine version to your mirror they should still be able to install packages. We can achieve this by using nginx to serve the mirrored content and use regex location matching to redirect requests to a public mirror.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s assume you chose to only mirror Alpine versions up from v3.13. If a client asks your mirror for v.3.10 it should redirect to another mirror.&lt;br /&gt;
&lt;br /&gt;
Your nginx config server block should look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
server {&lt;br /&gt;
        listen 80;&lt;br /&gt;
        server_name alpine.mydomain.local;&lt;br /&gt;
        root /data/alpine;          # point to where your alpine mirror is located. make sure nginx is allowed to read it&lt;br /&gt;
        autoindex on;               # Enable indexing&lt;br /&gt;
&lt;br /&gt;
        # the following location block will match for v3.0 to v3.12&lt;br /&gt;
        # and will forward it to dl-4.alpinelinux.org.&lt;br /&gt;
        location ~* /(v3\.([1-9]|1[012]))$&lt;br /&gt;
        {&lt;br /&gt;
          return 302 http://dl-cdn.alpinelinux.org/alpine$request_uri;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The corresponding sync script could look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env sh&lt;br /&gt;
&lt;br /&gt;
# make sure we never run 2 rsync at the same time&lt;br /&gt;
lockfile=&amp;quot;/tmp/alpine-mirror.lock&amp;quot;&lt;br /&gt;
if [ -z &amp;quot;$flock&amp;quot; ] ; then&lt;br /&gt;
  exec env flock=1 flock -n $lockfile &amp;quot;$0&amp;quot; &amp;quot;$@&amp;quot;&lt;br /&gt;
  fi&lt;br /&gt;
&lt;br /&gt;
  src=rsync://rsync.alpinelinux.org/alpine/&lt;br /&gt;
  dest=/data/alpine/&lt;br /&gt;
&lt;br /&gt;
  exclude=&amp;quot;--exclude v2.* --exclude v3.0 --exclude v3.1 --exclude v3.2 --exclude v3.3 --exclude v3.4 --exclude v3.5 --exclude v3.6 --exclude v3.7 --exclude v3.8 --exclude v3.9 --exclude v3.10 --exclude v3.11 --exclude v3.12&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  mkdir -p &amp;quot;$dest&amp;quot;&lt;br /&gt;
  /usr/bin/rsync -vvv \&lt;br /&gt;
  --archive \&lt;br /&gt;
  --update \&lt;br /&gt;
  --hard-links \&lt;br /&gt;
  --delete \&lt;br /&gt;
  --delete-after \&lt;br /&gt;
  --delete-excluded \&lt;br /&gt;
  --delay-updates \&lt;br /&gt;
  --timeout=600 \&lt;br /&gt;
  $exclude \&lt;br /&gt;
  &amp;quot;$src&amp;quot; &amp;quot;$dest&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Package Manager]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Apk_spec&amp;diff=22101</id>
		<title>Apk spec</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Apk_spec&amp;diff=22101"/>
		<updated>2022-07-18T03:32:32Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Draft}}&lt;br /&gt;
&lt;br /&gt;
For end-user facing documentation about apk, check out the [[Package_management]] page.&lt;br /&gt;
&lt;br /&gt;
This page is an attempt to document the internal data structures of the apk package manager. The canonical implementation of the apk format is [https://gitlab.alpinelinux.org/alpine/apk-tools apk-tools] and much of this information is gleaned from reading the source code.&lt;br /&gt;
&lt;br /&gt;
There are three generations of the APK data formats. Version 1 is deprecated and no longer used, version 2 is currently the main version in use by apk-tools, and version 3 is under development. This page mostly describes the data formats used in version 2.&lt;br /&gt;
&lt;br /&gt;
= Background =&lt;br /&gt;
== Tar Segments ==&lt;br /&gt;
Tar segments are a set of tar records. Normal tar files contain two null records at the end of the tar file to signal the end of the tarball. Tar segments are lacking these two records and can thus be concatenated before other tar files and will behave as one continuous tar file. The APK v2 package format makes use of both tar segments and tarballs.&lt;br /&gt;
&lt;br /&gt;
Tar segments can be compressed using gzip compression. Gzip is a stream-based file format and multiple streams can be concatenated together. Most tooling will treat multiple gzip streams within a file as if it were a single stream. APK v2 files are aware of gzip streams and use them for file segmentation.&lt;br /&gt;
&lt;br /&gt;
= Package Format V2 =&lt;br /&gt;
== Binary Format ==&lt;br /&gt;
APK v2 packages contain two tar segments followed by a tarball each in their own gzip stream (3 streams total). These streams contain the package signature, control data, and package data. The package data is a tarball of the files contained in a package laid out in a way that allows it to be unpacked at the filesystem root such that all files are placed in the correct location on the system. The control tar segment contains the package metadata along with any install scripts. The signature tar segment contains a single file that is a binary signature over the concatenated control segment and data tarball.&lt;br /&gt;
&lt;br /&gt;
The signature file is a DER encoded PKCS1v15 RSA signature of the SHA1 hash of the concatenated control and data gzip streams. The filename has the format &amp;lt;tt&amp;gt;.SIGN.RSA.&amp;lt;key_name&amp;gt;.rsa.pub&amp;lt;/tt&amp;gt; (for example &amp;lt;tt&amp;gt;.SIGN.RSA.alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub&amp;lt;/tt&amp;gt;). This file is placed inside of a tar record with permissions 0644, uid 0, and gid 0. This tar record (lacking end-of-tar records) is gzip compressed, forming a signature tar segment, and is concatenated onto the front of the combined control and data segments. [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild-sign.in abuild-sign] is responsible for generating these signature segments.&lt;br /&gt;
&lt;br /&gt;
The control segment contains the package metadata in a &amp;lt;tt&amp;gt;.PKGINFO&amp;lt;/tt&amp;gt; file as well as all of the scripts (if any) that are used by apk during installation and removal of the package. For historical reasons all files in the control tar segment are prefixed with a dot (&amp;lt;tt&amp;gt;.&amp;lt;/tt&amp;gt;). The control segment is constructed by placing each file for the package into a tar record, concatenating those tar records, gzipping the tar records, and concatenating them onto the front of the data tarball. The SHA1 hash of this gzip stream is used as the checksum &amp;lt;tt&amp;gt;C:&amp;lt;/tt&amp;gt; field in the APKINDEX file.&lt;br /&gt;
&lt;br /&gt;
The data tarball is a standard gzipped tarball with extra PAX headers that contain the SHA1 hash of each file in the tar header for that file. The hash is contained in a header called &amp;lt;tt&amp;gt;APK-TOOLS.checksum.SHA1&amp;lt;/tt&amp;gt;. Unlike the other tar streams this tarball does contain the two end-of-tar null records. It is always the final segment of an APK package. Hashes are added with the [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild-tar.c abuild-tar] tool.&lt;br /&gt;
&lt;br /&gt;
== PKGINFO Format ==&lt;br /&gt;
The PKGINFO file contains the package metadata. This is a plain-text file similar to INI files. Lines that begin with &amp;lt;tt&amp;gt;#&amp;lt;/tt&amp;gt; are comments and ignored. Unlike INI files the parsing format of this file is very strict. Each key-value pair must be separated by exactly one space, one equal sign, and one more space (&amp;lt;tt&amp;gt; = &amp;lt;/tt&amp;gt;). Keys may be repeated in this file and should be treated as a list of values if repetitions are found.&lt;br /&gt;
&lt;br /&gt;
The specification for what fields are valid in PKGINFO is largely defined by [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild.in abuild]. As of July 2022 the following fields are supported:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgname&amp;lt;/tt&amp;gt; - package name&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgver&amp;lt;/tt&amp;gt; - package version&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgdesc&amp;lt;/tt&amp;gt; - package description&lt;br /&gt;
* &amp;lt;tt&amp;gt;url&amp;lt;/tt&amp;gt; - package url&lt;br /&gt;
* &amp;lt;tt&amp;gt;builddate&amp;lt;/tt&amp;gt; - unix timestamp of the package build date/time&lt;br /&gt;
* &amp;lt;tt&amp;gt;packager&amp;lt;/tt&amp;gt; - name (and typically email) of person who built the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;size&amp;lt;/tt&amp;gt; - the installed-size of the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;arch&amp;lt;/tt&amp;gt; - the architecture of the package (ex: x86_64)&lt;br /&gt;
* &amp;lt;tt&amp;gt;origin&amp;lt;/tt&amp;gt; - the origin name of the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; - the commit hash from which the package was built&lt;br /&gt;
* &amp;lt;tt&amp;gt;maintainer&amp;lt;/tt&amp;gt; - name (and typically email) of the package maintainer&lt;br /&gt;
* &amp;lt;tt&amp;gt;replaces_priority&amp;lt;/tt&amp;gt; - replaces priority field for package (integer)&lt;br /&gt;
* &amp;lt;tt&amp;gt;provider_priority&amp;lt;/tt&amp;gt; - provider priority for the package (integer)&lt;br /&gt;
* &amp;lt;tt&amp;gt;license&amp;lt;/tt&amp;gt; - license string for the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;depend&amp;lt;/tt&amp;gt; - dependencies for the package (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;replaces&amp;lt;/tt&amp;gt; - packages this package replaces (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;provides&amp;lt;/tt&amp;gt; - what this package provides (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;triggers&amp;lt;/tt&amp;gt; - what packages this package triggers on (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;install_if&amp;lt;/tt&amp;gt; - install this package if these packages are present (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;datahash&amp;lt;/tt&amp;gt; - hex-encoded sha256 checksum of the data tarball&lt;br /&gt;
&lt;br /&gt;
== Example of PKGINFO ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Generated by abuild 3.9.0-r2&lt;br /&gt;
# using fakeroot version 1.25.3&lt;br /&gt;
# Wed Jul  6 19:09:49 UTC 2022&lt;br /&gt;
pkgname = busybox&lt;br /&gt;
pkgver = 1.35.0-r18&lt;br /&gt;
pkgdesc = Size optimized toolbox of many common UNIX utilities&lt;br /&gt;
url = https://busybox.net/&lt;br /&gt;
builddate = 1657134589&lt;br /&gt;
packager = Buildozer &amp;lt;alpine-devel@lists.alpinelinux.org&amp;gt;&lt;br /&gt;
size = 958464&lt;br /&gt;
arch = x86_64&lt;br /&gt;
origin = busybox&lt;br /&gt;
commit = 332d2fff53cd4537d415e15e55e8ceb6fe6eaedb&lt;br /&gt;
maintainer = Sören Tempel &amp;lt;soeren+alpine@soeren-tempel.net&amp;gt;&lt;br /&gt;
provider_priority = 100&lt;br /&gt;
license = GPL-2.0-only&lt;br /&gt;
replaces = busybox-initscripts&lt;br /&gt;
provides = /bin/sh&lt;br /&gt;
triggers = /bin /usr/bin /sbin /usr/sbin /lib/modules/*&lt;br /&gt;
# automatically detected:&lt;br /&gt;
provides = cmd:busybox=1.35.0-r18&lt;br /&gt;
provides = cmd:sh=1.35.0-r18&lt;br /&gt;
depend = so:libc.musl-x86_64.so.1&lt;br /&gt;
datahash = 7d3351ac6c3ebaf18182efb5390061f50d077ce5ade60a15909d91278f70ada7&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Package Building Example ==&lt;br /&gt;
This is a set of commands to partially build a package. &#039;&#039;&#039;DO NOT DO THIS&#039;&#039;&#039;, it&#039;s mainly an example to see how this all fits together. Use the official build tools to build packages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -c .PKGNIFO .pre-install | abuild-tar --cut | gzip -9 &amp;gt; $controldir/control.tar.gz&lt;br /&gt;
cd $pkgdir; tar -c * | abuild-tar --hash | gzip -9 &amp;gt; $controldir/data.tar.gz&lt;br /&gt;
cat $controldir/control.tar.gz $controldir/data.tar.gz &amp;gt; mypackage-1.0-r0.apk&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Index Format V2 =&lt;br /&gt;
== Binary Format ==&lt;br /&gt;
The index is served as [http://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz APKINDEX.tar.gz] and is downloaded by apk to power the package database. The index is signed similarly to packages. The main difference between the index and packages is that the index file contains only two segments.&lt;br /&gt;
&lt;br /&gt;
The signature segment is identical to a package segment and is concatenated, in its own gzip stream, to the beginning of the APKINDEX tarball.&lt;br /&gt;
&lt;br /&gt;
The APKINDEX tarball contains two files: a DESCRIPTION file and an APKINDEX file. Each of these files is in their own tar record and the final record is followed by the standard end-of-tar null records. The DESCRIPTION file is a simple text file containing a description of the index (ex: &amp;lt;tt&amp;gt;community v20210212-7170-g5c9853dc69&amp;lt;/tt&amp;gt;). The APKINDEX file is a text file containing records for each package in the repository in a text-based format. Each record is separated by a newline.&lt;br /&gt;
&lt;br /&gt;
== APKINDEX Format ==&lt;br /&gt;
The APKINDEX file contains a set of records extracted from the PKGINFO file of each package in the repository. Each line is prefixed with a letter, colon, and is followed by the value of the field. Lines are newline (&amp;lt;tt&amp;gt;\n&amp;lt;/tt&amp;gt;) terminated and there is one blank line between records for a package.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;apk_pkg_write_index_entry&amp;lt;/tt&amp;gt; function of [https://gitlab.alpinelinux.org/alpine/apk-tools/-/blob/ff7c8f6ee9dfa2add57b88dc271f6711030e72a0/src/package.c#L905 package.c] defines the currently accepted fields. As of July 2022, these are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;C:&amp;lt;/tt&amp;gt; - file checksum, see below&lt;br /&gt;
* &amp;lt;tt&amp;gt;P:&amp;lt;/tt&amp;gt; - package name (corresponds to &amp;lt;tt&amp;gt;pkgname&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;V:&amp;lt;/tt&amp;gt; - package version (corresponds to &amp;lt;tt&amp;gt;pkgver&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;A:&amp;lt;/tt&amp;gt; - architecture (corresponds to &amp;lt;tt&amp;gt;arch&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;S:&amp;lt;/tt&amp;gt; - size of entire package, integer&lt;br /&gt;
* &amp;lt;tt&amp;gt;I:&amp;lt;/tt&amp;gt; - installed size, integer (corresponds to &amp;lt;tt&amp;gt;size&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;T:&amp;lt;/tt&amp;gt; - description (corresponds to &amp;lt;tt&amp;gt;pkgdesc&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;U:&amp;lt;/tt&amp;gt; - url (corresponds to &amp;lt;tt&amp;gt;url&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;L:&amp;lt;/tt&amp;gt; - license (corresponds to &amp;lt;tt&amp;gt;license&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;o:&amp;lt;/tt&amp;gt; - origin (corresponds to &amp;lt;tt&amp;gt;origin&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;m:&amp;lt;/tt&amp;gt; - maintainer (corresponds to &amp;lt;tt&amp;gt;maintainer&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;t:&amp;lt;/tt&amp;gt; - build time (corresponds to &amp;lt;tt&amp;gt;builddate&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;c:&amp;lt;/tt&amp;gt; - commit (corresponds to &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;k:&amp;lt;/tt&amp;gt; - provider priority, integer (corresponds to &amp;lt;tt&amp;gt;provider_priority&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;D:&amp;lt;/tt&amp;gt; - dependencies (corresponds to &amp;lt;tt&amp;gt;depend&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
* &amp;lt;tt&amp;gt;p:&amp;lt;/tt&amp;gt; - provides (corresponds to &amp;lt;tt&amp;gt;provides&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
* &amp;lt;tt&amp;gt;i:&amp;lt;/tt&amp;gt; - install if (corresponds to &amp;lt;tt&amp;gt;install_if&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
&lt;br /&gt;
== Package Checksum Field ==&lt;br /&gt;
The package checksum field is the SHA1 hash of the second gzip stream (control stream) in the package. The binary hash digest is base64 encoded. This is prefixed with &amp;lt;tt&amp;gt;Q1&amp;lt;/tt&amp;gt; to differentiate it from the MD5 hashes used in older index formats. It is not possible to compute this checksum with standard command line tools but the apk-tools can compute it in their &amp;lt;tt&amp;gt;index&amp;lt;/tt&amp;gt; operation.&lt;br /&gt;
&lt;br /&gt;
== Example APKINDEX Record ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
C:Q1P4IRU/u5yB4CSnUEBRD1WWwajrY=&lt;br /&gt;
P:jool-tools&lt;br /&gt;
V:4.1.5-r0&lt;br /&gt;
A:x86_64&lt;br /&gt;
S:140605&lt;br /&gt;
I:434176&lt;br /&gt;
T:Userspace control tools for SIIT / NAT64 Jool&lt;br /&gt;
U:https://www.jool.mx&lt;br /&gt;
L:GPL-2.0-only&lt;br /&gt;
o:jool-tools&lt;br /&gt;
m:Jakub Jirutka &amp;lt;jakub@jirutka.cz&amp;gt;&lt;br /&gt;
t:1620480809&lt;br /&gt;
c:771b3b0910ea9c7736db6ca4ff5c37ca9cf9af0d&lt;br /&gt;
D:so:libc.musl-x86_64.so.1 so:libnl-3.so.200 so:libnl-genl-3.so.200&lt;br /&gt;
p:cmd:jool=4.1.5-r0 cmd:jool_siit=4.1.5-r0 cmd:joold=4.1.5-r0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Installed Database V2 =&lt;br /&gt;
The installed database is used by apk to track which packages are installed and what modifications those packages have made to the system. This file is located at &amp;lt;tt&amp;gt;/lib/apk/db/installed&amp;lt;/tt&amp;gt;. The installed file is a plaintext file of the same format as APKINDEX (contained in APKINDEX.tar.gz). It is neither compressed nor signed. Each record in the installed file starts with a package index record with the same fields as the APKINDEX file. The installed file adds some additional fields that are defined in [https://gitlab.alpinelinux.org/alpine/apk-tools/-/blob/ff7c8f6ee9dfa2add57b88dc271f6711030e72a0/src/database.c#L937 database.c]. As of July 2022 these additional fields are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;r:&amp;lt;/tt&amp;gt; - packages which this package replaces, space separated list&lt;br /&gt;
* &amp;lt;tt&amp;gt;q:&amp;lt;/tt&amp;gt; - replaces priority, integer, optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;s:&amp;lt;/tt&amp;gt; - repository tag, optional, this will be set if the package is tagged to a repository in the world file (ex: linux@testing)&lt;br /&gt;
* &amp;lt;tt&amp;gt;f:&amp;lt;/tt&amp;gt; - indicates broken items, space separated (f=files, s=scripts, x=xattrs, S=file hashes)&lt;br /&gt;
&lt;br /&gt;
The following fields are repeated and in groups consist of a set of mutations made to the system to install the package.&lt;br /&gt;
&lt;br /&gt;
ACL lines are specified as uid, colon, gid, colon, and mode.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;F:&amp;lt;/tt&amp;gt; - directory name that was created by package, repeated&lt;br /&gt;
* &amp;lt;tt&amp;gt;M:&amp;lt;/tt&amp;gt; - directory ACL, only if different than the default of 0:0:0755&lt;br /&gt;
* &amp;lt;tt&amp;gt;R:&amp;lt;/tt&amp;gt; - file name, relative to preceding directory name&lt;br /&gt;
* &amp;lt;tt&amp;gt;a:&amp;lt;/tt&amp;gt; - file ACL&lt;br /&gt;
* &amp;lt;tt&amp;gt;Z:&amp;lt;/tt&amp;gt; - file checksum, if the checksum in the package is not none, a &amp;lt;tt&amp;gt;Q1&amp;lt;/tt&amp;gt; prefix indicates this will be a SHA1 hash in base64 format&lt;br /&gt;
&lt;br /&gt;
[[Category:Package Manager]] [[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Apk_spec&amp;diff=22100</id>
		<title>Apk spec</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Apk_spec&amp;diff=22100"/>
		<updated>2022-07-18T01:41:09Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Draft}}&lt;br /&gt;
&lt;br /&gt;
For end-user facing documentation about apk, check out the [[Package_management]] page.&lt;br /&gt;
&lt;br /&gt;
This page is an attempt to document the internal data structures of the apk package manager. The canonical implementation of the apk format is [https://gitlab.alpinelinux.org/alpine/apk-tools apk-tools] and much of this information is gleaned from reading the source code.&lt;br /&gt;
&lt;br /&gt;
There are three generations of the APK data formats. Version 1 is deprecated and no longer used, version 2 is currently the main version in use by apk-tools, and version 3 is under development. This page mostly describes the data formats used in version 2.&lt;br /&gt;
&lt;br /&gt;
= Background =&lt;br /&gt;
== Tar Segments ==&lt;br /&gt;
Tar segments are a set of tar records. Normal tar files contain two null records at the end of the tar file to signal the end of the tarball. Tar segments are lacking these two records and can thus be concatenated before other tar files and will behave as one continuous tar file. The APK v2 package format makes use of both tar segments and tarballs.&lt;br /&gt;
&lt;br /&gt;
Tar segments can be compressed using gzip compression. Gzip is a stream-based file format and multiple streams can be concatenated together. Most tooling will treat multiple gzip streams within a file as if it were a single stream. APK v2 files are aware of gzip streams and use them for file segmentation.&lt;br /&gt;
&lt;br /&gt;
= Package Format V2 =&lt;br /&gt;
== Binary Format ==&lt;br /&gt;
APK v2 packages contain two tar segments followed by a tarball each in their own gzip stream (3 streams total). These streams contain the package signature, control data, and package data. The package data is a tarball of the files contained in a package laid out in a way that allows it to be unpacked at the filesystem root such that all files are placed in the correct location on the system. The control tar segment contains the package metadata along with any install scripts. The signature tar segment contains a single file that is a binary signature over the concatenated control segment and data tarball.&lt;br /&gt;
&lt;br /&gt;
The signature file is a DER encoded PKCS1v15 RSA signature of the SHA1 hash of the concatenated control and data gzip streams. The filename has the format &amp;lt;tt&amp;gt;.SIGN.RSA.&amp;lt;key_name&amp;gt;.rsa.pub&amp;lt;/tt&amp;gt; (for example &amp;lt;tt&amp;gt;.SIGN.RSA.alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub&amp;lt;/tt&amp;gt;). This file is placed inside of a tar record with permissions 0644, uid 0, and gid 0. This tar record (lacking end-of-tar records) is gzip compressed, forming a signature tar segment, and is concatenated onto the front of the combined control and data segments. [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild-sign.in abuild-sign] is responsible for generating these signature segments.&lt;br /&gt;
&lt;br /&gt;
The control segment contains the package metadata in a &amp;lt;tt&amp;gt;.PKGINFO&amp;lt;/tt&amp;gt; file as well as all of the scripts (if any) that are used by apk during installation and removal of the package. For historical reasons all files in the control tar segment are prefixed with a dot (&amp;lt;tt&amp;gt;.&amp;lt;/tt&amp;gt;). The control segment is constructed by placing each file for the package into a tar record, concatenating those tar records, gzipping the tar records, and concatenating them onto the front of the data tarball. The SHA1 hash of this gzip stream is used as the checksum &amp;lt;tt&amp;gt;C:&amp;lt;/tt&amp;gt; field in the APKINDEX file.&lt;br /&gt;
&lt;br /&gt;
The data tarball is a standard gzipped tarball with extra PAX headers that contain the SHA1 hash of each file in the tar header for that file. The hash is contained in a header called &amp;lt;tt&amp;gt;APK-TOOLS.checksum.SHA1&amp;lt;/tt&amp;gt;. Unlike the other tar streams this tarball does contain the two end-of-tar null records. It is always the final segment of an APK package. Hashes are added with the [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild-tar.c abuild-tar] tool.&lt;br /&gt;
&lt;br /&gt;
== PKGINFO Format ==&lt;br /&gt;
The PKGINFO file contains the package metadata. This is a plain-text file similar to INI files. Lines that begin with &amp;lt;tt&amp;gt;#&amp;lt;/tt&amp;gt; are comments and ignored. Unlike INI files the parsing format of this file is very strict. Each key-value pair must be separated by exactly one space, one equal sign, and one more space (&amp;lt;tt&amp;gt; = &amp;lt;/tt&amp;gt;). Keys may be repeated in this file and should be treated as a list of values if repetitions are found.&lt;br /&gt;
&lt;br /&gt;
The specification for what fields are valid in PKGINFO is largely defined by [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild.in abuild]. As of July 2022 the following fields are supported:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgname&amp;lt;/tt&amp;gt; - package name&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgver&amp;lt;/tt&amp;gt; - package version&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgdesc&amp;lt;/tt&amp;gt; - package description&lt;br /&gt;
* &amp;lt;tt&amp;gt;url&amp;lt;/tt&amp;gt; - package url&lt;br /&gt;
* &amp;lt;tt&amp;gt;builddate&amp;lt;/tt&amp;gt; - unix timestamp of the package build date/time&lt;br /&gt;
* &amp;lt;tt&amp;gt;packager&amp;lt;/tt&amp;gt; - name (and typically email) of person who built the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;size&amp;lt;/tt&amp;gt; - the installed-size of the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;arch&amp;lt;/tt&amp;gt; - the architecture of the package (ex: x86_64)&lt;br /&gt;
* &amp;lt;tt&amp;gt;origin&amp;lt;/tt&amp;gt; - the origin name of the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; - the commit hash from which the package was built&lt;br /&gt;
* &amp;lt;tt&amp;gt;maintainer&amp;lt;/tt&amp;gt; - name (and typically email) of the package maintainer&lt;br /&gt;
* &amp;lt;tt&amp;gt;replaces_priority&amp;lt;/tt&amp;gt; - replaces priority field for package (integer)&lt;br /&gt;
* &amp;lt;tt&amp;gt;provider_priority&amp;lt;/tt&amp;gt; - provider priority for the package (integer)&lt;br /&gt;
* &amp;lt;tt&amp;gt;license&amp;lt;/tt&amp;gt; - license string for the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;depend&amp;lt;/tt&amp;gt; - dependencies for the package (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;replaces&amp;lt;/tt&amp;gt; - packages this package replaces (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;provides&amp;lt;/tt&amp;gt; - what this package provides (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;triggers&amp;lt;/tt&amp;gt; - what packages this package triggers on (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;install_if&amp;lt;/tt&amp;gt; - install this package if these packages are present (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;datahash&amp;lt;/tt&amp;gt; - hex-encoded sha256 checksum of the data tarball&lt;br /&gt;
&lt;br /&gt;
== Example of PKGINFO ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Generated by abuild 3.9.0-r2&lt;br /&gt;
# using fakeroot version 1.25.3&lt;br /&gt;
# Wed Jul  6 19:09:49 UTC 2022&lt;br /&gt;
pkgname = busybox&lt;br /&gt;
pkgver = 1.35.0-r18&lt;br /&gt;
pkgdesc = Size optimized toolbox of many common UNIX utilities&lt;br /&gt;
url = https://busybox.net/&lt;br /&gt;
builddate = 1657134589&lt;br /&gt;
packager = Buildozer &amp;lt;alpine-devel@lists.alpinelinux.org&amp;gt;&lt;br /&gt;
size = 958464&lt;br /&gt;
arch = x86_64&lt;br /&gt;
origin = busybox&lt;br /&gt;
commit = 332d2fff53cd4537d415e15e55e8ceb6fe6eaedb&lt;br /&gt;
maintainer = Sören Tempel &amp;lt;soeren+alpine@soeren-tempel.net&amp;gt;&lt;br /&gt;
provider_priority = 100&lt;br /&gt;
license = GPL-2.0-only&lt;br /&gt;
replaces = busybox-initscripts&lt;br /&gt;
provides = /bin/sh&lt;br /&gt;
triggers = /bin /usr/bin /sbin /usr/sbin /lib/modules/*&lt;br /&gt;
# automatically detected:&lt;br /&gt;
provides = cmd:busybox=1.35.0-r18&lt;br /&gt;
provides = cmd:sh=1.35.0-r18&lt;br /&gt;
depend = so:libc.musl-x86_64.so.1&lt;br /&gt;
datahash = 7d3351ac6c3ebaf18182efb5390061f50d077ce5ade60a15909d91278f70ada7&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Package Building Example ==&lt;br /&gt;
This is a set of commands to partially build a package. &#039;&#039;&#039;DO NOT DO THIS&#039;&#039;&#039;, it&#039;s mainly an example to see how this all fits together. Use the official build tools to build packages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -c .PKGNIFO .pre-install | abuild-tar --cut | gzip -9 &amp;gt; $controldir/control.tar.gz&lt;br /&gt;
cd $pkgdir; tar -c * | abuild-tar --hash | gzip -9 &amp;gt; $controldir/data.tar.gz&lt;br /&gt;
cat $controldir/control.tar.gz $controldir/data.tar.gz &amp;gt; mypackage-1.0-r0.apk&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Index Format V2 =&lt;br /&gt;
== Binary Format ==&lt;br /&gt;
The index is served as [http://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz APKINDEX.tar.gz] and is downloaded by apk to power the package database. The index is signed similarly to packages. The main difference between the index and packages is that the index file contains only two segments.&lt;br /&gt;
&lt;br /&gt;
The signature segment is identical to a package segment and is concatenated, in its own gzip stream, to the beginning of the APKINDEX tarball.&lt;br /&gt;
&lt;br /&gt;
The APKINDEX tarball contains two files: a DESCRIPTION file and an APKINDEX file. Each of these files is in their own tar record and the final record is followed by the standard end-of-tar null records. The DESCRIPTION file is a simple text file containing a description of the index (ex: &amp;lt;tt&amp;gt;community v20210212-7170-g5c9853dc69&amp;lt;/tt&amp;gt;). The APKINDEX file is a text file containing records for each package in the repository in a text-based format. Each record is separated by a newline.&lt;br /&gt;
&lt;br /&gt;
== APKINDEX Format ==&lt;br /&gt;
The APKINDEX file contains a set of records extracted from the PKGINFO file of each package in the repository. Each line is prefixed with a letter, colon, and is followed by the value of the field. Lines are newline (&amp;lt;tt&amp;gt;\n&amp;lt;/tt&amp;gt;) terminated and there is one blank line between records for a package.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;apk_pkg_write_index_entry&amp;lt;/tt&amp;gt; function of [https://gitlab.alpinelinux.org/alpine/apk-tools/-/blob/ff7c8f6ee9dfa2add57b88dc271f6711030e72a0/src/package.c#L905 package.c] defines the currently accepted fields. As of July 2022, these are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;C:&amp;lt;/tt&amp;gt; - file checksum, see below&lt;br /&gt;
* &amp;lt;tt&amp;gt;P:&amp;lt;/tt&amp;gt; - package name (corresponds to &amp;lt;tt&amp;gt;pkgname&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;V:&amp;lt;/tt&amp;gt; - package version (corresponds to &amp;lt;tt&amp;gt;pkgver&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;A:&amp;lt;/tt&amp;gt; - architecture (corresponds to &amp;lt;tt&amp;gt;arch&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;S:&amp;lt;/tt&amp;gt; - size of entire package, integer&lt;br /&gt;
* &amp;lt;tt&amp;gt;I:&amp;lt;/tt&amp;gt; - installed size, integer (corresponds to &amp;lt;tt&amp;gt;size&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;T:&amp;lt;/tt&amp;gt; - description (corresponds to &amp;lt;tt&amp;gt;pkgdesc&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;U:&amp;lt;/tt&amp;gt; - url (corresponds to &amp;lt;tt&amp;gt;url&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;L:&amp;lt;/tt&amp;gt; - license (corresponds to &amp;lt;tt&amp;gt;license&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;o:&amp;lt;/tt&amp;gt; - origin (corresponds to &amp;lt;tt&amp;gt;origin&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;m:&amp;lt;/tt&amp;gt; - maintainer (corresponds to &amp;lt;tt&amp;gt;maintainer&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;t:&amp;lt;/tt&amp;gt; - build time (corresponds to &amp;lt;tt&amp;gt;builddate&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;c:&amp;lt;/tt&amp;gt; - commit (corresponds to &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;k:&amp;lt;/tt&amp;gt; - provider priority, integer (corresponds to &amp;lt;tt&amp;gt;provider_priority&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;D:&amp;lt;/tt&amp;gt; - dependencies (corresponds to &amp;lt;tt&amp;gt;depend&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
* &amp;lt;tt&amp;gt;p:&amp;lt;/tt&amp;gt; - provides (corresponds to &amp;lt;tt&amp;gt;provides&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
* &amp;lt;tt&amp;gt;i:&amp;lt;/tt&amp;gt; - install if (corresponds to &amp;lt;tt&amp;gt;install_if&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
&lt;br /&gt;
== Package Checksum Field ==&lt;br /&gt;
The package checksum field is the SHA1 hash of the second gzip stream (control stream) in the package. The binary hash digest is base64 encoded. This is prefixed with &amp;lt;tt&amp;gt;Q1&amp;lt;/tt&amp;gt; to differentiate it from the MD5 hashes used in older index formats. It is not possible to compute this checksum with standard command line tools but the apk-tools can compute it in their &amp;lt;tt&amp;gt;index&amp;lt;/tt&amp;gt; operation.&lt;br /&gt;
&lt;br /&gt;
== Example APKINDEX Record ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
C:Q1P4IRU/u5yB4CSnUEBRD1WWwajrY=&lt;br /&gt;
P:jool-tools&lt;br /&gt;
V:4.1.5-r0&lt;br /&gt;
A:x86_64&lt;br /&gt;
S:140605&lt;br /&gt;
I:434176&lt;br /&gt;
T:Userspace control tools for SIIT / NAT64 Jool&lt;br /&gt;
U:https://www.jool.mx&lt;br /&gt;
L:GPL-2.0-only&lt;br /&gt;
o:jool-tools&lt;br /&gt;
m:Jakub Jirutka &amp;lt;jakub@jirutka.cz&amp;gt;&lt;br /&gt;
t:1620480809&lt;br /&gt;
c:771b3b0910ea9c7736db6ca4ff5c37ca9cf9af0d&lt;br /&gt;
D:so:libc.musl-x86_64.so.1 so:libnl-3.so.200 so:libnl-genl-3.so.200&lt;br /&gt;
p:cmd:jool=4.1.5-r0 cmd:jool_siit=4.1.5-r0 cmd:joold=4.1.5-r0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Package Manager]] [[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Apk_spec&amp;diff=22099</id>
		<title>Apk spec</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Apk_spec&amp;diff=22099"/>
		<updated>2022-07-18T01:39:26Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Draft}}&lt;br /&gt;
&lt;br /&gt;
For end-user facing documentation about apk, check out the [[Package_management]] page.&lt;br /&gt;
&lt;br /&gt;
This page is an attempt to document the internal data structures of the apk package manager. The canonical implementation of the apk format is [https://gitlab.alpinelinux.org/alpine/apk-tools apk-tools] and much of this information is gleaned from reading the source code.&lt;br /&gt;
&lt;br /&gt;
There are three generations of the APK data formats. Version 1 is deprecated and no longer used, version 2 is currently the main version in use by apk-tools, and version 3 is under development. This page mostly describes the data formats used in version 2.&lt;br /&gt;
&lt;br /&gt;
= Package Format V2 =&lt;br /&gt;
== Tar Segments ==&lt;br /&gt;
Tar segments are a set of tar records. Normal tar files contain two null records at the end of the tar file to signal the end of the tarball. Tar segments are lacking these two records and can thus be concatenated before other tar files and will behave as one continuous tar file. The APK v2 package format makes use of both tar segments and tarballs.&lt;br /&gt;
&lt;br /&gt;
Tar segments can be compressed using gzip compression. Gzip is a stream-based file format and multiple streams can be concatenated together. Most tooling will treat multiple gzip streams within a file as if it were a single stream. APK v2 files are aware of gzip streams and use them for file segmentation.&lt;br /&gt;
&lt;br /&gt;
== Binary Format ==&lt;br /&gt;
APK v2 packages contain two tar segments followed by a tarball each in their own gzip stream (3 streams total). These streams contain the package signature, control data, and package data. The package data is a tarball of the files contained in a package laid out in a way that allows it to be unpacked at the filesystem root such that all files are placed in the correct location on the system. The control tar segment contains the package metadata along with any install scripts. The signature tar segment contains a single file that is a binary signature over the concatenated control segment and data tarball.&lt;br /&gt;
&lt;br /&gt;
The signature file is a DER encoded PKCS1v15 RSA signature of the SHA1 hash of the concatenated control and data gzip streams. The filename has the format &amp;lt;tt&amp;gt;.SIGN.RSA.&amp;lt;key_name&amp;gt;.rsa.pub&amp;lt;/tt&amp;gt; (for example &amp;lt;tt&amp;gt;.SIGN.RSA.alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub&amp;lt;/tt&amp;gt;). This file is placed inside of a tar record with permissions 0644, uid 0, and gid 0. This tar record (lacking end-of-tar records) is gzip compressed, forming a signature tar segment, and is concatenated onto the front of the combined control and data segments. [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild-sign.in abuild-sign] is responsible for generating these signature segments.&lt;br /&gt;
&lt;br /&gt;
The control segment contains the package metadata in a &amp;lt;tt&amp;gt;.PKGINFO&amp;lt;/tt&amp;gt; file as well as all of the scripts (if any) that are used by apk during installation and removal of the package. For historical reasons all files in the control tar segment are prefixed with a dot (&amp;lt;tt&amp;gt;.&amp;lt;/tt&amp;gt;). The control segment is constructed by placing each file for the package into a tar record, concatenating those tar records, gzipping the tar records, and concatenating them onto the front of the data tarball. The SHA1 hash of this gzip stream is used as the checksum &amp;lt;tt&amp;gt;C:&amp;lt;/tt&amp;gt; field in the APKINDEX file.&lt;br /&gt;
&lt;br /&gt;
The data tarball is a standard gzipped tarball with extra PAX headers that contain the SHA1 hash of each file in the tar header for that file. The hash is contained in a header called &amp;lt;tt&amp;gt;APK-TOOLS.checksum.SHA1&amp;lt;/tt&amp;gt;. Unlike the other tar streams this tarball does contain the two end-of-tar null records. It is always the final segment of an APK package. Hashes are added with the [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild-tar.c abuild-tar] tool.&lt;br /&gt;
&lt;br /&gt;
== PKGINFO Format ==&lt;br /&gt;
The PKGINFO file contains the package metadata. This is a plain-text file similar to INI files. Lines that begin with &amp;lt;tt&amp;gt;#&amp;lt;/tt&amp;gt; are comments and ignored. Unlike INI files the parsing format of this file is very strict. Each key-value pair must be separated by exactly one space, one equal sign, and one more space (&amp;lt;tt&amp;gt; = &amp;lt;/tt&amp;gt;). Keys may be repeated in this file and should be treated as a list of values if repetitions are found.&lt;br /&gt;
&lt;br /&gt;
The specification for what fields are valid in PKGINFO is largely defined by [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild.in abuild]. As of July 2022 the following fields are supported:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgname&amp;lt;/tt&amp;gt; - package name&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgver&amp;lt;/tt&amp;gt; - package version&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgdesc&amp;lt;/tt&amp;gt; - package description&lt;br /&gt;
* &amp;lt;tt&amp;gt;url&amp;lt;/tt&amp;gt; - package url&lt;br /&gt;
* &amp;lt;tt&amp;gt;builddate&amp;lt;/tt&amp;gt; - unix timestamp of the package build date/time&lt;br /&gt;
* &amp;lt;tt&amp;gt;packager&amp;lt;/tt&amp;gt; - name (and typically email) of person who built the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;size&amp;lt;/tt&amp;gt; - the installed-size of the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;arch&amp;lt;/tt&amp;gt; - the architecture of the package (ex: x86_64)&lt;br /&gt;
* &amp;lt;tt&amp;gt;origin&amp;lt;/tt&amp;gt; - the origin name of the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; - the commit hash from which the package was built&lt;br /&gt;
* &amp;lt;tt&amp;gt;maintainer&amp;lt;/tt&amp;gt; - name (and typically email) of the package maintainer&lt;br /&gt;
* &amp;lt;tt&amp;gt;replaces_priority&amp;lt;/tt&amp;gt; - replaces priority field for package (integer)&lt;br /&gt;
* &amp;lt;tt&amp;gt;provider_priority&amp;lt;/tt&amp;gt; - provider priority for the package (integer)&lt;br /&gt;
* &amp;lt;tt&amp;gt;license&amp;lt;/tt&amp;gt; - license string for the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;depend&amp;lt;/tt&amp;gt; - dependencies for the package (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;replaces&amp;lt;/tt&amp;gt; - packages this package replaces (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;provides&amp;lt;/tt&amp;gt; - what this package provides (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;triggers&amp;lt;/tt&amp;gt; - what packages this package triggers on (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;install_if&amp;lt;/tt&amp;gt; - install this package if these packages are present (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;datahash&amp;lt;/tt&amp;gt; - hex-encoded sha256 checksum of the data tarball&lt;br /&gt;
&lt;br /&gt;
== Example of PKGINFO ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Generated by abuild 3.9.0-r2&lt;br /&gt;
# using fakeroot version 1.25.3&lt;br /&gt;
# Wed Jul  6 19:09:49 UTC 2022&lt;br /&gt;
pkgname = busybox&lt;br /&gt;
pkgver = 1.35.0-r18&lt;br /&gt;
pkgdesc = Size optimized toolbox of many common UNIX utilities&lt;br /&gt;
url = https://busybox.net/&lt;br /&gt;
builddate = 1657134589&lt;br /&gt;
packager = Buildozer &amp;lt;alpine-devel@lists.alpinelinux.org&amp;gt;&lt;br /&gt;
size = 958464&lt;br /&gt;
arch = x86_64&lt;br /&gt;
origin = busybox&lt;br /&gt;
commit = 332d2fff53cd4537d415e15e55e8ceb6fe6eaedb&lt;br /&gt;
maintainer = Sören Tempel &amp;lt;soeren+alpine@soeren-tempel.net&amp;gt;&lt;br /&gt;
provider_priority = 100&lt;br /&gt;
license = GPL-2.0-only&lt;br /&gt;
replaces = busybox-initscripts&lt;br /&gt;
provides = /bin/sh&lt;br /&gt;
triggers = /bin /usr/bin /sbin /usr/sbin /lib/modules/*&lt;br /&gt;
# automatically detected:&lt;br /&gt;
provides = cmd:busybox=1.35.0-r18&lt;br /&gt;
provides = cmd:sh=1.35.0-r18&lt;br /&gt;
depend = so:libc.musl-x86_64.so.1&lt;br /&gt;
datahash = 7d3351ac6c3ebaf18182efb5390061f50d077ce5ade60a15909d91278f70ada7&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Package Building Example ==&lt;br /&gt;
This is a set of commands to partially build a package. &#039;&#039;&#039;DO NOT DO THIS&#039;&#039;&#039;, it&#039;s mainly an example to see how this all fits together. Use the official build tools to build packages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -c .PKGNIFO .pre-install | abuild-tar --cut | gzip -9 &amp;gt; $controldir/control.tar.gz&lt;br /&gt;
cd $pkgdir; tar -c * | abuild-tar --hash | gzip -9 &amp;gt; $controldir/data.tar.gz&lt;br /&gt;
cat $controldir/control.tar.gz $controldir/data.tar.gz &amp;gt; mypackage-1.0-r0.apk&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Index Format V2 =&lt;br /&gt;
== Binary Format ==&lt;br /&gt;
The index is served as [http://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz APKINDEX.tar.gz] and is downloaded by apk to power the package database. The index is signed similarly to packages. The main difference between the index and packages is that the index file contains only two segments.&lt;br /&gt;
&lt;br /&gt;
The signature segment is identical to a package segment and is concatenated, in its own gzip stream, to the beginning of the APKINDEX tarball.&lt;br /&gt;
&lt;br /&gt;
The APKINDEX tarball contains two files: a DESCRIPTION file and an APKINDEX file. Each of these files is in their own tar record and the final record is followed by the standard end-of-tar null records. The DESCRIPTION file is a simple text file containing a description of the index (ex: &amp;lt;tt&amp;gt;community v20210212-7170-g5c9853dc69&amp;lt;/tt&amp;gt;). The APKINDEX file is a text file containing records for each package in the repository in a text-based format. Each record is separated by a newline.&lt;br /&gt;
&lt;br /&gt;
== APKINDEX Format ==&lt;br /&gt;
The APKINDEX file contains a set of records extracted from the PKGINFO file of each package in the repository. Each line is prefixed with a letter, colon, and is followed by the value of the field. Lines are newline (&amp;lt;tt&amp;gt;\n&amp;lt;/tt&amp;gt;) terminated and there is one blank line between records for a package.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;apk_pkg_write_index_entry&amp;lt;/tt&amp;gt; function of [https://gitlab.alpinelinux.org/alpine/apk-tools/-/blob/ff7c8f6ee9dfa2add57b88dc271f6711030e72a0/src/package.c#L905 package.c] defines the currently accepted fields. As of July 2022, these are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;C:&amp;lt;/tt&amp;gt; - file checksum, see below&lt;br /&gt;
* &amp;lt;tt&amp;gt;P:&amp;lt;/tt&amp;gt; - package name (corresponds to &amp;lt;tt&amp;gt;pkgname&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;V:&amp;lt;/tt&amp;gt; - package version (corresponds to &amp;lt;tt&amp;gt;pkgver&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;A:&amp;lt;/tt&amp;gt; - architecture (corresponds to &amp;lt;tt&amp;gt;arch&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;S:&amp;lt;/tt&amp;gt; - size of entire package, integer&lt;br /&gt;
* &amp;lt;tt&amp;gt;I:&amp;lt;/tt&amp;gt; - installed size, integer (corresponds to &amp;lt;tt&amp;gt;size&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;T:&amp;lt;/tt&amp;gt; - description (corresponds to &amp;lt;tt&amp;gt;pkgdesc&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;U:&amp;lt;/tt&amp;gt; - url (corresponds to &amp;lt;tt&amp;gt;url&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;L:&amp;lt;/tt&amp;gt; - license (corresponds to &amp;lt;tt&amp;gt;license&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;o:&amp;lt;/tt&amp;gt; - origin (corresponds to &amp;lt;tt&amp;gt;origin&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;m:&amp;lt;/tt&amp;gt; - maintainer (corresponds to &amp;lt;tt&amp;gt;maintainer&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;t:&amp;lt;/tt&amp;gt; - build time (corresponds to &amp;lt;tt&amp;gt;builddate&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;c:&amp;lt;/tt&amp;gt; - commit (corresponds to &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;k:&amp;lt;/tt&amp;gt; - provider priority, integer (corresponds to &amp;lt;tt&amp;gt;provider_priority&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;D:&amp;lt;/tt&amp;gt; - dependencies (corresponds to &amp;lt;tt&amp;gt;depend&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
* &amp;lt;tt&amp;gt;p:&amp;lt;/tt&amp;gt; - provides (corresponds to &amp;lt;tt&amp;gt;provides&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
* &amp;lt;tt&amp;gt;i:&amp;lt;/tt&amp;gt; - install if (corresponds to &amp;lt;tt&amp;gt;install_if&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
&lt;br /&gt;
== Package Checksum Field ==&lt;br /&gt;
The package checksum field is the SHA1 hash of the second gzip stream (control stream) in the package. The binary hash digest is base64 encoded. This is prefixed with &amp;lt;tt&amp;gt;Q1&amp;lt;/tt&amp;gt; to differentiate it from the MD5 hashes used in older index formats. It is not possible to compute this checksum with standard command line tools but the apk-tools can compute it in their &amp;lt;tt&amp;gt;index&amp;lt;/tt&amp;gt; operation.&lt;br /&gt;
&lt;br /&gt;
== Example APKINDEX Record ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
C:Q1P4IRU/u5yB4CSnUEBRD1WWwajrY=&lt;br /&gt;
P:jool-tools&lt;br /&gt;
V:4.1.5-r0&lt;br /&gt;
A:x86_64&lt;br /&gt;
S:140605&lt;br /&gt;
I:434176&lt;br /&gt;
T:Userspace control tools for SIIT / NAT64 Jool&lt;br /&gt;
U:https://www.jool.mx&lt;br /&gt;
L:GPL-2.0-only&lt;br /&gt;
o:jool-tools&lt;br /&gt;
m:Jakub Jirutka &amp;lt;jakub@jirutka.cz&amp;gt;&lt;br /&gt;
t:1620480809&lt;br /&gt;
c:771b3b0910ea9c7736db6ca4ff5c37ca9cf9af0d&lt;br /&gt;
D:so:libc.musl-x86_64.so.1 so:libnl-3.so.200 so:libnl-genl-3.so.200&lt;br /&gt;
p:cmd:jool=4.1.5-r0 cmd:jool_siit=4.1.5-r0 cmd:joold=4.1.5-r0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Package Manager]] [[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Apk_internals&amp;diff=22098</id>
		<title>Apk internals</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Apk_internals&amp;diff=22098"/>
		<updated>2022-07-18T01:38:18Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: Redirected page to Apk spec&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Apk_spec]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Apkindex_format&amp;diff=22097</id>
		<title>Apkindex format</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Apkindex_format&amp;diff=22097"/>
		<updated>2022-07-18T01:38:16Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: Redirected page to Apk spec&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Apk_spec]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Alpine_package_format&amp;diff=22096</id>
		<title>Alpine package format</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Alpine_package_format&amp;diff=22096"/>
		<updated>2022-07-18T01:38:06Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: Redirected page to Apk spec&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Apk_spec]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Apk_spec&amp;diff=22095</id>
		<title>Apk spec</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Apk_spec&amp;diff=22095"/>
		<updated>2022-07-18T01:37:23Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Draft}}&lt;br /&gt;
&lt;br /&gt;
For end-user facing documentation about apk, check out the [[Package_management]] page.&lt;br /&gt;
&lt;br /&gt;
This page is an attempt to document the internal data structures of the apk package manager. The canonical implementation of the apk format is [https://gitlab.alpinelinux.org/alpine/apk-tools apk-tools] and much of this information is gleaned from reading the source code.&lt;br /&gt;
&lt;br /&gt;
There are three generations of the APK data formats. Version 1 is deprecated and no longer used, version 2 is currently the main version in use by apk-tools, and version 3 is under development. This page mostly describes the data formats used in version 2.&lt;br /&gt;
&lt;br /&gt;
= Package Format V2 =&lt;br /&gt;
== Tar Segments ==&lt;br /&gt;
Tar segments are a set of tar records. Normal tar files contain two null records at the end of the tar file to signal the end of the tarball. Tar segments are lacking these two records and can thus be concatenated before other tar files and will behave as one continuous tar file. The APK v2 package format makes use of both tar segments and tarballs.&lt;br /&gt;
&lt;br /&gt;
Tar segments can be compressed using gzip compression. Gzip is a stream-based file format and multiple streams can be concatenated together. Most tooling will treat multiple gzip streams within a file as if it were a single stream. APK v2 files are aware of gzip streams and use them for file segmentation.&lt;br /&gt;
&lt;br /&gt;
== Binary Format ==&lt;br /&gt;
APK v2 packages contain two tar segments followed by a tarball each in their own gzip stream (3 streams total). These streams contain the package signature, control data, and package data. The package data is a tarball of the files contained in a package laid out in a way that allows it to be unpacked at the filesystem root such that all files are placed in the correct location on the system. The control tar segment contains the package metadata along with any install scripts. The signature tar segment contains a single file that is a binary signature over the concatenated control segment and data tarball.&lt;br /&gt;
&lt;br /&gt;
The signature file is a DER encoded PKCS1v15 RSA signature of the SHA1 hash of the concatenated control and data gzip streams. The filename has the format &amp;lt;tt&amp;gt;.SIGN.RSA.&amp;lt;key_name&amp;gt;.rsa.pub&amp;lt;/tt&amp;gt; (for example &amp;lt;tt&amp;gt;.SIGN.RSA.alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub&amp;lt;/tt&amp;gt;). This file is placed inside of a tar record with permissions 0644, uid 0, and gid 0. This tar record (lacking end-of-tar records) is gzip compressed, forming a signature tar segment, and is concatenated onto the front of the combined control and data segments. [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild-sign.in abuild-sign] is responsible for generating these signature segments.&lt;br /&gt;
&lt;br /&gt;
The control segment contains the package metadata in a &amp;lt;tt&amp;gt;.PKGINFO&amp;lt;/tt&amp;gt; file as well as all of the scripts (if any) that are used by apk during installation and removal of the package. For historical reasons all files in the control tar segment are prefixed with a dot (&amp;lt;tt&amp;gt;.&amp;lt;/tt&amp;gt;). The control segment is constructed by placing each file for the package into a tar record, concatenating those tar records, gzipping the tar records, and concatenating them onto the front of the data tarball. The SHA1 hash of this gzip stream is used as the checksum &amp;lt;tt&amp;gt;C:&amp;lt;/tt&amp;gt; field in the APKINDEX file.&lt;br /&gt;
&lt;br /&gt;
The data tarball is a standard gzipped tarball with extra PAX headers that contain the SHA1 hash of each file in the tar header for that file. The hash is contained in a header called &amp;lt;tt&amp;gt;APK-TOOLS.checksum.SHA1&amp;lt;/tt&amp;gt;. Unlike the other tar streams this tarball does contain the two end-of-tar null records. It is always the final segment of an APK package. Hashes are added with the [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild-tar.c abuild-tar] tool.&lt;br /&gt;
&lt;br /&gt;
== PKGINFO Format ==&lt;br /&gt;
The PKGINFO file contains the package metadata. This is a plain-text file similar to INI files. Lines that begin with &amp;lt;tt&amp;gt;#&amp;lt;/tt&amp;gt; are comments and ignored. Unlike INI files the parsing format of this file is very strict. Each key-value pair must be separated by exactly one space, one equal sign, and one more space (&amp;lt;tt&amp;gt; = &amp;lt;/tt&amp;gt;). Keys may be repeated in this file and should be treated as a list of values if repetitions are found.&lt;br /&gt;
&lt;br /&gt;
The specification for what fields are valid in PKGINFO is largely defined by [https://gitlab.alpinelinux.org/alpine/abuild/-/blob/master/abuild.in abuild]. As of July 2022 the following fields are supported:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgname&amp;lt;/tt&amp;gt; - package name&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgver&amp;lt;/tt&amp;gt; - package version&lt;br /&gt;
* &amp;lt;tt&amp;gt;pkgdesc&amp;lt;/tt&amp;gt; - package description&lt;br /&gt;
* &amp;lt;tt&amp;gt;url&amp;lt;/tt&amp;gt; - package url&lt;br /&gt;
* &amp;lt;tt&amp;gt;builddate&amp;lt;/tt&amp;gt; - unix timestamp of the package build date/time&lt;br /&gt;
* &amp;lt;tt&amp;gt;packager&amp;lt;/tt&amp;gt; - name (and typically email) of person who built the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;size&amp;lt;/tt&amp;gt; - the installed-size of the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;arch&amp;lt;/tt&amp;gt; - the architecture of the package (ex: x86_64)&lt;br /&gt;
* &amp;lt;tt&amp;gt;origin&amp;lt;/tt&amp;gt; - the origin name of the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; - the commit hash from which the package was built&lt;br /&gt;
* &amp;lt;tt&amp;gt;maintainer&amp;lt;/tt&amp;gt; - name (and typically email) of the package maintainer&lt;br /&gt;
* &amp;lt;tt&amp;gt;replaces_priority&amp;lt;/tt&amp;gt; - replaces priority field for package (integer)&lt;br /&gt;
* &amp;lt;tt&amp;gt;provider_priority&amp;lt;/tt&amp;gt; - provider priority for the package (integer)&lt;br /&gt;
* &amp;lt;tt&amp;gt;license&amp;lt;/tt&amp;gt; - license string for the package&lt;br /&gt;
* &amp;lt;tt&amp;gt;depend&amp;lt;/tt&amp;gt; - dependencies for the package (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;replaces&amp;lt;/tt&amp;gt; - packages this package replaces (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;provides&amp;lt;/tt&amp;gt; - what this package provides (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;triggers&amp;lt;/tt&amp;gt; - what packages this package triggers on (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;install_if&amp;lt;/tt&amp;gt; - install this package if these packages are present (repeated)&lt;br /&gt;
* &amp;lt;tt&amp;gt;datahash&amp;lt;/tt&amp;gt; - hex-encoded sha256 checksum of the data tarball&lt;br /&gt;
&lt;br /&gt;
== Example of PKGINFO ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Generated by abuild 3.9.0-r2&lt;br /&gt;
# using fakeroot version 1.25.3&lt;br /&gt;
# Wed Jul  6 19:09:49 UTC 2022&lt;br /&gt;
pkgname = busybox&lt;br /&gt;
pkgver = 1.35.0-r18&lt;br /&gt;
pkgdesc = Size optimized toolbox of many common UNIX utilities&lt;br /&gt;
url = https://busybox.net/&lt;br /&gt;
builddate = 1657134589&lt;br /&gt;
packager = Buildozer &amp;lt;alpine-devel@lists.alpinelinux.org&amp;gt;&lt;br /&gt;
size = 958464&lt;br /&gt;
arch = x86_64&lt;br /&gt;
origin = busybox&lt;br /&gt;
commit = 332d2fff53cd4537d415e15e55e8ceb6fe6eaedb&lt;br /&gt;
maintainer = Sören Tempel &amp;lt;soeren+alpine@soeren-tempel.net&amp;gt;&lt;br /&gt;
provider_priority = 100&lt;br /&gt;
license = GPL-2.0-only&lt;br /&gt;
replaces = busybox-initscripts&lt;br /&gt;
provides = /bin/sh&lt;br /&gt;
triggers = /bin /usr/bin /sbin /usr/sbin /lib/modules/*&lt;br /&gt;
# automatically detected:&lt;br /&gt;
provides = cmd:busybox=1.35.0-r18&lt;br /&gt;
provides = cmd:sh=1.35.0-r18&lt;br /&gt;
depend = so:libc.musl-x86_64.so.1&lt;br /&gt;
datahash = 7d3351ac6c3ebaf18182efb5390061f50d077ce5ade60a15909d91278f70ada7&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Package Building Example ==&lt;br /&gt;
This is a set of commands to partially build a package. &#039;&#039;&#039;DO NOT DO THIS&#039;&#039;&#039;, it&#039;s mainly an example to see how this all fits together. Use the official build tools to build packages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
tar -c .PKGNIFO .pre-install | abuild-tar --cut | gzip -9 &amp;gt; $controldir/control.tar.gz&lt;br /&gt;
cd $pkgdir; tar -c * | abuild-tar --hash | gzip -9 &amp;gt; $controldir/data.tar.gz&lt;br /&gt;
cat $controldir/control.tar.gz $controldir/data.tar.gz &amp;gt; mypackage-1.0-r0.apk&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Index Format V2 =&lt;br /&gt;
== Binary Format ==&lt;br /&gt;
The index is served as [http://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz APKINDEX.tar.gz] and is downloaded by apk to power the package database. The index is signed similarly to packages. The main difference between the index and packages is that the index file contains only two segments.&lt;br /&gt;
&lt;br /&gt;
The signature segment is identical to a package segment and is concatenated, in its own gzip stream, to the beginning of the APKINDEX tarball.&lt;br /&gt;
&lt;br /&gt;
The APKINDEX tarball contains two files: a DESCRIPTION file and an APKINDEX file. Each of these files is in their own tar record and the final record is followed by the standard end-of-tar null records. The DESCRIPTION file is a simple text file containing a description of the index (ex: &amp;lt;tt&amp;gt;community v20210212-7170-g5c9853dc69&amp;lt;/tt&amp;gt;). The APKINDEX file is a text file containing records for each package in the repository in a text-based format. Each record is separated by a newline.&lt;br /&gt;
&lt;br /&gt;
== APKINDEX Format ==&lt;br /&gt;
The APKINDEX file contains a set of records extracted from the PKGINFO file of each package in the repository. Each line is prefixed with a letter, colon, and is followed by the value of the field. Lines are newline (&amp;lt;tt&amp;gt;\n&amp;lt;/tt&amp;gt;) terminated and there is one blank line between records for a package.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;apk_pkg_write_index_entry&amp;lt;/tt&amp;gt; function of [https://gitlab.alpinelinux.org/alpine/apk-tools/-/blob/ff7c8f6ee9dfa2add57b88dc271f6711030e72a0/src/package.c#L905 package.c] defines the currently accepted fields. As of July 2022, these are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;C:&amp;lt;/tt&amp;gt; - file checksum, the SHA1 hash of the second gzip stream of the package, base64-encoded and prefixed with &amp;lt;tt&amp;gt;Q1&amp;lt;/tt&amp;gt; to indicate SHA1&lt;br /&gt;
* &amp;lt;tt&amp;gt;P:&amp;lt;/tt&amp;gt; - package name (corresponds to &amp;lt;tt&amp;gt;pkgname&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;V:&amp;lt;/tt&amp;gt; - package version (corresponds to &amp;lt;tt&amp;gt;pkgver&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;A:&amp;lt;/tt&amp;gt; - architecture (corresponds to &amp;lt;tt&amp;gt;arch&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;S:&amp;lt;/tt&amp;gt; - size of entire package, integer&lt;br /&gt;
* &amp;lt;tt&amp;gt;I:&amp;lt;/tt&amp;gt; - installed size, integer (corresponds to &amp;lt;tt&amp;gt;size&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;T:&amp;lt;/tt&amp;gt; - description (corresponds to &amp;lt;tt&amp;gt;pkgdesc&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;U:&amp;lt;/tt&amp;gt; - url (corresponds to &amp;lt;tt&amp;gt;url&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;L:&amp;lt;/tt&amp;gt; - license (corresponds to &amp;lt;tt&amp;gt;license&amp;lt;/tt&amp;gt; in PKGINFO)&lt;br /&gt;
* &amp;lt;tt&amp;gt;o:&amp;lt;/tt&amp;gt; - origin (corresponds to &amp;lt;tt&amp;gt;origin&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;m:&amp;lt;/tt&amp;gt; - maintainer (corresponds to &amp;lt;tt&amp;gt;maintainer&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;t:&amp;lt;/tt&amp;gt; - build time (corresponds to &amp;lt;tt&amp;gt;builddate&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;c:&amp;lt;/tt&amp;gt; - commit (corresponds to &amp;lt;tt&amp;gt;commit&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;k:&amp;lt;/tt&amp;gt; - provider priority, integer (corresponds to &amp;lt;tt&amp;gt;provider_priority&amp;lt;/tt&amp;gt; in PKGINFO), optional&lt;br /&gt;
* &amp;lt;tt&amp;gt;D:&amp;lt;/tt&amp;gt; - dependencies (corresponds to &amp;lt;tt&amp;gt;depend&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
* &amp;lt;tt&amp;gt;p:&amp;lt;/tt&amp;gt; - provides (corresponds to &amp;lt;tt&amp;gt;provides&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
* &amp;lt;tt&amp;gt;i:&amp;lt;/tt&amp;gt; - install if (corresponds to &amp;lt;tt&amp;gt;install_if&amp;lt;/tt&amp;gt; in PKGINFO, concatenated by spaces into a single line)&lt;br /&gt;
&lt;br /&gt;
== Package Checksum Field ==&lt;br /&gt;
The package checksum field is the SHA1 hash of the second gzip stream (control stream) in the package. The binary hash digest is base64 encoded. This is prefixed with &amp;lt;tt&amp;gt;Q1&amp;lt;/tt&amp;gt; to differentiate it from the MD5 hashes used in older index formats. It is not possible to compute this checksum with standard command line tools but the apk-tools can compute it in their &amp;lt;tt&amp;gt;index&amp;lt;/tt&amp;gt; operation.&lt;br /&gt;
&lt;br /&gt;
== Example APKINDEX Record ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
C:Q1P4IRU/u5yB4CSnUEBRD1WWwajrY=&lt;br /&gt;
P:jool-tools&lt;br /&gt;
V:4.1.5-r0&lt;br /&gt;
A:x86_64&lt;br /&gt;
S:140605&lt;br /&gt;
I:434176&lt;br /&gt;
T:Userspace control tools for SIIT / NAT64 Jool&lt;br /&gt;
U:https://www.jool.mx&lt;br /&gt;
L:GPL-2.0-only&lt;br /&gt;
o:jool-tools&lt;br /&gt;
m:Jakub Jirutka &amp;lt;jakub@jirutka.cz&amp;gt;&lt;br /&gt;
t:1620480809&lt;br /&gt;
c:771b3b0910ea9c7736db6ca4ff5c37ca9cf9af0d&lt;br /&gt;
D:so:libc.musl-x86_64.so.1 so:libnl-3.so.200 so:libnl-genl-3.so.200&lt;br /&gt;
p:cmd:jool=4.1.5-r0 cmd:jool_siit=4.1.5-r0 cmd:joold=4.1.5-r0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Package Manager]] [[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Migrating_data&amp;diff=17679</id>
		<title>Migrating data</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Migrating_data&amp;diff=17679"/>
		<updated>2020-06-01T01:52:32Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: Remove tools that don&amp;#039;t work on Alpine&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;We compare several methods for copying/migrating large amounts of data. The aim is to preserve all file permissions and metadata, which will require root access on both source and target filesystems.&lt;br /&gt;
&lt;br /&gt;
We include information about some options that aren&#039;t available on BusyBox&#039;s implementation of these tools, because you may be copying data to/from systems with other Unix tools installed, which do provide those options.&lt;br /&gt;
&lt;br /&gt;
{{Warning| None of the methods below will copy the [[Partitioning and Bootmanagers|bootmanager]] (ext/syslinux, grub, etc) to a new drive; you&#039;ll have to install it there explicitly.}}&lt;br /&gt;
&lt;br /&gt;
== Bit-copying methods ==&lt;br /&gt;
&lt;br /&gt;
If your source data occupies an entire partition (that is, nothing else resides on that partition), and your target partition is the same size or larger, and you&#039;re willing to have it use the same filesystem as the source, then one option is to bit-copy the whole source partition:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Boot from LiveCD and make sure that neither /dev/&amp;lt;var&amp;gt;sourcepart&amp;lt;/var&amp;gt; nor /dev/&amp;lt;var&amp;gt;targetpart&amp;lt;/var&amp;gt; are mounted.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
{{Cmd| dd bs{{=}}10M if{{=}}/dev/&amp;lt;var&amp;gt;sourcepart&amp;lt;/var&amp;gt; of{{=}}/dev/&amp;lt;var&amp;gt;targetpart&amp;lt;/var&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
This also copies unoccupied blocks on the &amp;lt;var&amp;gt;sourcepart&amp;lt;/var&amp;gt; to the &amp;lt;var&amp;gt;targetpart&amp;lt;/var&amp;gt;. A more optimal variant is to use [http://www.partimage.org/Main_Page partimage], which copies only the used portions of the sourcepart. One limitation is that currently (v0.6.9, released July 2010, current as of Mar 2012) partimage doesn&#039;t support ext4 format.&lt;br /&gt;
&lt;br /&gt;
{{Todo| Generally the target partition will have same partition type (e.g., Linux 0x83) as the source; but is this strictly necessary?}}&lt;br /&gt;
&lt;br /&gt;
Once you&#039;ve finished, the filesystem on &amp;lt;var&amp;gt;targetpart&amp;lt;/var&amp;gt; may occupy less than the total space available on &amp;lt;var&amp;gt;targetpart&amp;lt;/var&amp;gt;. You may want to use [[Filesystems|a tool like resize2fs]] to grow the partition.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Higher-level methods ==&lt;br /&gt;
&lt;br /&gt;
The other options we&#039;ll discuss suppose that the target filesystem is already formatted and mounted as {{Path|/target}}. &lt;br /&gt;
&lt;br /&gt;
If you&#039;re proposing to copy volatile data from a running system, you may want to copy from a lvm snapshot, or do the copy from single-user mode, or from a LiveCD or other boot medium so that your source data is no longer in use during the copy. If you&#039;re just proposing to copy from {{Path|/home}} or such, no such precautions are necessary.&lt;br /&gt;
&lt;br /&gt;
If you&#039;re copying a complete filesystem, you&#039;ll probably only want to copy the {{Path|/sys}} and {{Path|/proc}} mountpoints, but not their current contents. Remember to copy {{Path|/boot}} and {{Path|/dev}} and {{Path|/tmp}}, the last two of which may require special attention. Pay attention to other mountpoints (such as {{Path|/mnt}}, {{Path|/media}}) and RAM-based filesystems (such as {{Path|/run}} and {{Path|/lib/rc/init.d}}).&lt;br /&gt;
&lt;br /&gt;
{{Todo|The preceding comments assume you know what you are doing, and only serve as reminders. Would be good to link to a fuller explanation.}}&lt;br /&gt;
&lt;br /&gt;
{{Note| /dev is tricky nowadays on some systems since it&#039;s hidden by udev. Here&#039;s a possible solution:&lt;br /&gt;
{{Cmd|mkdir /tmp/dev&lt;br /&gt;
mount --move /dev /tmp/dev&lt;br /&gt;
&amp;lt;i&amp;gt;copy /dev to /mnt/sdb5 using one of the methods elsewhere on this page&amp;lt;/i&amp;gt;&lt;br /&gt;
mount --move /tmp/dev /dev&lt;br /&gt;
rmdir /tmp/dev}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== cp ===&lt;br /&gt;
Depending on what system you&#039;re working with, and what kind of data you&#039;re copying, you &#039;&#039;may&#039;&#039; be able to do a satisfactory &#039;&#039;local&#039;&#039; copy using just &amp;lt;code&amp;gt;cp&amp;lt;/code&amp;gt;. But there are a number of limits here that prevent this from being a general solution.&lt;br /&gt;
&lt;br /&gt;
The Gnu implementation of &amp;lt;code&amp;gt;cp&amp;lt;/code&amp;gt; provides the following options (among others):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-a&amp;lt;/code&amp;gt;: same as &amp;lt;code&amp;gt;-RP -p/--preserve=mode,ownership,timestamps,links,context,xattr&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt;: verbose&lt;br /&gt;
* &amp;lt;code&amp;gt;-l&amp;lt;/code&amp;gt;: make hard links instead of copying&lt;br /&gt;
* &amp;lt;code&amp;gt;-s&amp;lt;/code&amp;gt;: make symlinks instead of copying (source file names must be absolute)&lt;br /&gt;
* &amp;lt;code&amp;gt;--sparse=always&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--update&amp;lt;/code&amp;gt;: don&#039;t copy files or symlinks over an existing file unless its mtime is older&lt;br /&gt;
* &amp;lt;code&amp;gt;-x&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--one-file-system&amp;lt;/code&amp;gt;: skip subdirectories on different volumes&lt;br /&gt;
    &lt;br /&gt;
The BusyBox version provides all of the Gnu options except &amp;lt;code&amp;gt;--sparse&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-x&amp;lt;/code&amp;gt;, and may lack the &amp;lt;code&amp;gt;context&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;xattr&amp;lt;/code&amp;gt; options to &amp;lt;code&amp;gt;--preserve&amp;lt;/code&amp;gt;. It will preserve hard links: if {{Path|/source/A}} and {{Path|/source/B}} are hard links, {{Path|/target/A}} and {{Path|/target/B}} will also be hard links with each other (though not with the originals). BusyBox&#039;s &amp;lt;code&amp;gt;cp&amp;lt;/code&amp;gt; seems to silently ignore the &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt; option.&lt;br /&gt;
&lt;br /&gt;
The FreeBSD implementation provides all of these except &amp;lt;code&amp;gt;-s&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;--sparse&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt;, and the &amp;lt;code&amp;gt;--preserve&amp;lt;/code&amp;gt; options from &amp;lt;code&amp;gt;links&amp;lt;/code&amp;gt; on: in particular, it always copies hard links as separate files. The Mac version shares the limitations of the FreeBSD version, and additionally lacks &amp;lt;code&amp;gt;-x&amp;lt;/code&amp;gt;. Also, on the Mac version the &amp;lt;code&amp;gt;-a&amp;lt;/code&amp;gt; shortcut isn&#039;t available, you must explicitly say &amp;lt;code&amp;gt;-RPp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Note| As just explained, some of these implementations will break hard links.}}&lt;br /&gt;
&lt;br /&gt;
{{Warning| Avoid the lower-case &amp;lt;code&amp;gt;-r&amp;lt;/code&amp;gt; option. Its behavior varies between implementations, and may diverge from what you want for special files or symlinks.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== tar ===&lt;br /&gt;
&lt;br /&gt;
Options recognized by BusyBox and other implementations:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-c&amp;lt;/code&amp;gt;: create a new archive, records existing perms and mtimes, symbolic owner/group (can specify &amp;lt;code&amp;gt;--numeric-owner&amp;lt;/code&amp;gt;), hard links among archive elements&lt;br /&gt;
* &amp;lt;code&amp;gt;-x&amp;lt;/code&amp;gt;: extract files from an archive, uses current owner/group unless root, subtracts current umask unless root or &amp;lt;code&amp;gt;-p&amp;lt;/code&amp;gt;, when extracting hard links must include first&lt;br /&gt;
* &amp;lt;code&amp;gt;-t&amp;lt;/code&amp;gt;: list the contents of an archive&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-f &amp;lt;var&amp;gt;archive&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;: use &amp;lt;code&amp;gt;-f -&amp;lt;/code&amp;gt; for stdin/stdout&lt;br /&gt;
: {{Note| On some but not all implementations, the archive defaults to stdin/stdout when &amp;lt;code&amp;gt;-f&amp;lt;/code&amp;gt; is not supplied. It&#039;s most portable to always declare this explicitly.}}&lt;br /&gt;
* &amp;lt;code&amp;gt;-O&amp;lt;/code&amp;gt;: extract files to standard output&lt;br /&gt;
* &amp;lt;code&amp;gt;-C &amp;lt;var&amp;gt;dir&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;: change to directory &amp;lt;var&amp;gt;dir&amp;lt;/var&amp;gt;, when creating this is order-sensitive&lt;br /&gt;
* &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt;: verbose&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-z&amp;lt;/code&amp;gt;: compress archive with gzip&lt;br /&gt;
* &amp;lt;code&amp;gt;-j&amp;lt;/code&amp;gt;: compress archive with bzip2&lt;br /&gt;
* &amp;lt;code&amp;gt;-Z&amp;lt;/code&amp;gt;: compress archive with compress&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-h&amp;lt;/code&amp;gt;: follow symlinks, archive and extract the files they point to (like &amp;lt;code&amp;gt;-L&amp;lt;/code&amp;gt; in other programs)&lt;br /&gt;
* &amp;lt;code&amp;gt;-m&amp;lt;/code&amp;gt;: don&#039;t extract file&#039;s original mtime, leave touched with the extraction time&lt;br /&gt;
* &amp;lt;code&amp;gt;-T &amp;lt;var&amp;gt;file&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;: get names to extract or create from &amp;lt;var&amp;gt;file&amp;lt;/var&amp;gt;, which can also include &amp;quot;-C/etc&amp;quot; lines&lt;br /&gt;
* &amp;lt;code&amp;gt;--exclude=&amp;lt;var&amp;gt;pattern&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;: exclude specified glob &amp;lt;var&amp;gt;pattern&amp;lt;/var&amp;gt;s&lt;br /&gt;
* &amp;lt;code&amp;gt;-X &amp;lt;var&amp;gt;file&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;: exclude glob patterns listed in &amp;lt;var&amp;gt;file&amp;lt;/var&amp;gt;&lt;br /&gt;
: {{Note| Default globbing rules: (i) matches after any /, not just at ^; (ii) case-sensitive; (iii) wildcards match /}}&lt;br /&gt;
&lt;br /&gt;
The following common options are allegedly also honored by BusyBox (according to&lt;br /&gt;
comments in its source) but aren&#039;t declared in its &amp;lt;code&amp;gt;--help&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-o&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--no-same-owner&amp;lt;/code&amp;gt;: (BSD doesn&#039;t recognize a long option) extract as yourself (default for ordinary users)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-p&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--same-permissions&amp;lt;/code&amp;gt;: (BSD doesn&#039;t recognize this long option) extract permissions verbatim, instead of subtracting current umask (usually default for root)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;--no-same-permissions&amp;lt;/code&amp;gt;: subtract umask from extracted permissions (default for ordinary users)&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;--numeric-owner&amp;lt;/code&amp;gt;: create using numbers for user/groups&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-k&amp;lt;/code&amp;gt;: don&#039;t replace existing files when extracting&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;--overwrite&amp;lt;/code&amp;gt;: (not on BSD) more aggressively overwrite existing files and directory metadata when extracting&amp;lt;br /&amp;gt;&lt;br /&gt;
      tar&#039;s default behavior is to first remove existing files (otherwise, all their hardlinks would be modified) and symlinks.&lt;br /&gt;
      If an existing dir is nonempty, its existing contents won&#039;t be removed; tar will instead just update the dir&#039;s metadata.&lt;br /&gt;
      &amp;lt;code&amp;gt;--overwrite&amp;lt;/code&amp;gt; instead &#039;&#039;follows&#039;&#039; existing symlinks, and removes anything that impedes extraction except non-empty dirs.&lt;br /&gt;
      (Gnu&#039;s &amp;lt;code&amp;gt;--recursive-unlink&amp;lt;/code&amp;gt; removes even those, may replace them with files or symlinks.)&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gnu options (also Mac and FreeBSD unless noted) also include:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;--one-file-system&amp;lt;/code&amp;gt;: when creating archive, stay on the volume(s) where the specified roots are located, and don&#039;t cross mountpoints&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;--null&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;-T&amp;lt;/code&amp;gt; reads null-terminated names, ignores &amp;quot;-C/etc&amp;quot; entries&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-l&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--check-links&amp;lt;/code&amp;gt;: (BSD for &amp;lt;code&amp;gt;-c&amp;lt;/code&amp;gt; only) when creating or extracting, print a message if not all hard links are processed&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-S&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;--sparse&amp;lt;/code&amp;gt;: (not on BSD) when creating archive, handle sparse files efficiently&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Some Gnu tar formats:&lt;br /&gt;
* in future, will default to &amp;lt;code&amp;gt;-H posix/pax&amp;lt;/code&amp;gt;, which is the POSIX.1-2001 format&lt;br /&gt;
* v.1.13 - current (v1.26 released Mar 2011, still current in Mar 2012): defaults to &amp;lt;code&amp;gt;-H gnu&amp;lt;/code&amp;gt;, which is not very different from the &amp;lt;code&amp;gt;-H oldgnu&amp;lt;/code&amp;gt; format.&lt;br /&gt;
* &amp;lt;code&amp;gt;-H ustar&amp;lt;/code&amp;gt; is the portable POSIX.1-1988 format, some limits including max 256 char filenames, max 8G filesize; supports special files, but not sparse files; also seems not to support xattrs and ACLs (other tar formats are meant to handle ACLs, but see [[#tar_acl|comments below]])&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example of local copy:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|sudo tar -cf- [--one-file-system] /source {{!}} sudo tar -xp[v]f- -C /target}}&lt;br /&gt;
&lt;br /&gt;
The optional flags are:&lt;br /&gt;
* &amp;lt;code&amp;gt;--one-file-system&amp;lt;/code&amp;gt;: Stay on the volume where {{Path|/source}} is located. This may or may not be the behavior you desire. Note that this feature isn&#039;t available on BusyBox &amp;lt;code&amp;gt;tar&amp;lt;/code&amp;gt; in any case, though it is available in some other &amp;lt;code&amp;gt;tar&amp;lt;/code&amp;gt; implementations.&lt;br /&gt;
* &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt;: verbose&lt;br /&gt;
&lt;br /&gt;
Example of using tar in cpio-style (for which, see below):&lt;br /&gt;
{{Cmd|cd /source&lt;br /&gt;
sudo find . [-xdev] -depth [-print0] {{!}} sudo tar -cf- -T- [--null] {{!}} sudo tar -xp[v]f- -C /target}}&lt;br /&gt;
&lt;br /&gt;
The next examples add the &amp;lt;code&amp;gt;-z&amp;lt;/code&amp;gt; flag, to compress output using gzip. If you have a fast connection, you may omit this; alternatively, you may use &amp;lt;code&amp;gt;-j&amp;lt;/code&amp;gt; for bzip2. Example of copying to remote machine:&lt;br /&gt;
{{Cmd|sudo tar -czf- [--one-file-system] /source {{!}} ssh root@machine &amp;quot;tar -xpz[v]f- -C /target&amp;quot;}}&lt;br /&gt;
&lt;br /&gt;
Example of copying from remote machine:&lt;br /&gt;
{{Cmd|ssh root@machine &amp;quot;tar -czf- [--one-file-system] /source&amp;quot; {{!}} sudo tar -xpz[v]f- -C /target}}&lt;br /&gt;
&lt;br /&gt;
=== cpio ===&lt;br /&gt;
&lt;br /&gt;
cpio operates in one of these four modes:&lt;br /&gt;
* &amp;lt;code&amp;gt;-o -H newc&amp;lt;/code&amp;gt;: create archive on stdout (or &amp;lt;code&amp;gt;-F &amp;lt;var&amp;gt;archive&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;), including filenames supplied from stdin (like &amp;lt;code&amp;gt;tar -cf- -T-&amp;lt;/code&amp;gt;)&lt;br /&gt;
: &amp;lt;code&amp;gt;-H newc&amp;lt;/code&amp;gt;: (on Mac, &amp;lt;code&amp;gt;-H sv4cpio&amp;lt;/code&amp;gt; and/or &amp;lt;code&amp;gt;-c&amp;lt;/code&amp;gt;) specifies to use SVR4 ASCII format, this is required to create archives in BusyBox&lt;br /&gt;
* &amp;lt;code&amp;gt;-i&amp;lt;/code&amp;gt;: receive archive from stdin (or &amp;lt;code&amp;gt;-F &amp;lt;var&amp;gt;archive&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;), extract specified patterns underneath curdir (like &amp;lt;code&amp;gt;tar -xf-&amp;lt;/code&amp;gt;)&lt;br /&gt;
* &amp;lt;code&amp;gt;-t&amp;lt;/code&amp;gt;: (on some systems, may need &amp;lt;code&amp;gt;-it&amp;lt;/code&amp;gt;) receive archive from stdin (or &amp;lt;code&amp;gt;-F &amp;lt;var&amp;gt;archive&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;), list contents to stdout (like &amp;lt;code&amp;gt;tar -tf-&amp;lt;/code&amp;gt;)&lt;br /&gt;
* &amp;lt;code&amp;gt;-p /target&amp;lt;/code&amp;gt;: receive list of files from stdin (or &amp;lt;code&amp;gt;-F &amp;lt;var&amp;gt;archive&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;), copy them underneath {{Path|/target}} (like &amp;lt;code&amp;gt;tar -cf- -T- | tar -xf- -C /target&amp;lt;/code&amp;gt;) &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
tar vs cpio:&lt;br /&gt;
* if you have includes/excludes, it&#039;s easier to use &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; than unfamiliar and non-portable options of Gnu tar&lt;br /&gt;
* cpio handles special files (block and char devices, fifos, etc); traditional tar (&amp;lt;code&amp;gt;-H v7&amp;lt;/code&amp;gt; format) didn&#039;t, also didn&#039;t store symbolic owner/group&lt;br /&gt;
* when extracting hard links, tar must always include the first&lt;br /&gt;
* tar and the &amp;lt;code&amp;gt;-H newc&amp;lt;/code&amp;gt; cpio format handle 32-bit inodes; though some older cpio formats didn&#039;t&lt;br /&gt;
* the &amp;lt;code&amp;gt;-H newc&amp;lt;/code&amp;gt; cpio format has max 1024 char filenames (though Gnu cpio can handle arbitrary lengths) and max 4G filesize; the portable &amp;lt;code&amp;gt;-H ustar&amp;lt;/code&amp;gt; tar format has max 256 char filenames and max 8G filesize&lt;br /&gt;
* in some implementations, cpio wouldn&#039;t copy files over 2G properly; don&#039;t have details about which implementations/versions are so limited&lt;br /&gt;
* &amp;lt;span id=&amp;quot;tar_acl&amp;quot;&amp;gt;some tar formats are supposed to handle acls, however [http://unix.stackexchange.com/q/391/4801 in practice this doesn&#039;t seem very reliable]; not sure what the situation is with cpio; rsync is known to work well for such cases&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Some more info: http://www.suse.de/~aj/linux_lfs.html --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example of local copy:&lt;br /&gt;
{{Cmd|cd /source&lt;br /&gt;
sudo find . [-xdev] -depth [\! -path ./lost+found] [-print0] {{!}} sudo cpio -pdm[vul] [-0] /target}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The flags are:&lt;br /&gt;
* &amp;lt;code&amp;gt;-xdev&amp;lt;/code&amp;gt;: stay on the volume where {{Path|/source}} is located; this may or may not be the behavior you desire&lt;br /&gt;
* &amp;lt;code&amp;gt;\! -path ./lost+found&amp;lt;/code&amp;gt;: omit empty {{Path|./lost+found}}; &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; only needs to be escaped for some shells, and this sequence may be repeated&lt;br /&gt;
* &amp;lt;code&amp;gt;-print0&amp;lt;/code&amp;gt; ... &amp;lt;code&amp;gt;-0&amp;lt;/code&amp;gt;: permits processing filenames with embedded &amp;lt;code&amp;gt;\n&amp;lt;/code&amp;gt;s, not available on BusyBox &amp;lt;code&amp;gt;cpio&amp;lt;/code&amp;gt; or Mac&lt;br /&gt;
* &amp;lt;code&amp;gt;-d&amp;lt;/code&amp;gt;: create leading directories, like &amp;lt;code&amp;gt;mkdir -p&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;-m&amp;lt;/code&amp;gt;: preserve file&#039;s original mtime&lt;br /&gt;
* &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt;: verbose&lt;br /&gt;
* &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt;: overwrite existing files, even if they&#039;re newer than files being copied&lt;br /&gt;
* &amp;lt;code&amp;gt;-l&amp;lt;/code&amp;gt;: create hard links instead of copying. This may or may not be the behavior you desire. Note that this feature isn&#039;t available on BusyBox &amp;lt;code&amp;gt;cpio&amp;lt;/code&amp;gt; in any case, though it is available in some other &amp;lt;code&amp;gt;cpio&amp;lt;/code&amp;gt; implementations.&lt;br /&gt;
&lt;br /&gt;
Other flags are:&lt;br /&gt;
* &amp;lt;code&amp;gt;-oA -F &amp;lt;var&amp;gt;archive&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt;: append to existing archive (not on BusyBox or BSD)&lt;br /&gt;
* &amp;lt;code&amp;gt;-L&amp;lt;/code&amp;gt;: follow symlinks (not on BusyBox)&lt;br /&gt;
* &amp;lt;code&amp;gt;--sparse&amp;lt;/code&amp;gt;: write files with blocks of zeros as sparse files (Gnu only)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example of copying to remote machine:&lt;br /&gt;
{{Cmd|cd /source&lt;br /&gt;
sudo find . [-xdev] -depth [-print0] {{!}} sudo cpio -o -H newc [-0] {{!}} [gzip -3 {{!}}] ssh root@machine &amp;quot;cd /target; gunzip {{!}} cpio -idm[vu]&amp;quot;}}&lt;br /&gt;
&lt;br /&gt;
=== rsync ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;rsync&amp;lt;/code&amp;gt; must be installed on both source and target machines. Example:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|rsync -a[vzx] --delete [--numeric-ids] [-HAX] [--exclude{{=}}/proc --exclude{{=}}/dev --exclude{{=}}/sys] /source/ [root@machine:]/target}}&lt;br /&gt;
&lt;br /&gt;
Note that the trailing {{Path|/}} on {{Path|/source/}} is essential, if you want {{Path|/target}} to end up a clone of {{Path|/source}}.&lt;br /&gt;
&lt;br /&gt;
The flags are:&lt;br /&gt;
* &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt;: verbose&lt;br /&gt;
* &amp;lt;code&amp;gt;-z&amp;lt;/code&amp;gt;: compress data during transfer&lt;br /&gt;
* &amp;lt;code&amp;gt;-x&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;--one-file-system&amp;lt;/code&amp;gt;: skip subdirectories on different volumes&lt;br /&gt;
* &amp;lt;code&amp;gt;--numeric-ids&amp;lt;/code&amp;gt;: rsync&#039;s default is to use symbolic user/groupnames&lt;br /&gt;
* &amp;lt;code&amp;gt;-H&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;--hard-links&amp;lt;/code&amp;gt;: preserve hard links in copied data, this can be expensive, and won&#039;t break existing hard links on {{Path|/target}} unless rsync needed to write updated data to some of the linked files&lt;br /&gt;
* &amp;lt;code&amp;gt;-A&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;--acls&amp;lt;/code&amp;gt;: preserve ACLs&lt;br /&gt;
* &amp;lt;code&amp;gt;-X&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;--xattrs&amp;lt;/code&amp;gt;: preserve xattrs&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;-8&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;--8-bit-output&amp;lt;/code&amp;gt;: don&#039;t escape chars in filename even if they&#039;re invalid in current locale&lt;br /&gt;
* &amp;lt;code&amp;gt;--partial&amp;lt;/code&amp;gt;: keep partially-transferred files&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;code&amp;gt;--inplace&amp;lt;/code&amp;gt;: overwrite existing files in place&amp;lt;br /&amp;gt;&lt;br /&gt;
rsync&#039;s default behavior is to write new files and move them into place when complete; this breaks any hard links the existing file may have had and makes a copy-on-write filesystem see the file as entirely new. &amp;lt;code&amp;gt;--inplace&amp;lt;/code&amp;gt; specifies an alternate behavior, of writing updated data directly into the existing file.&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;-h&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;--human-readable&amp;lt;/code&amp;gt;: report statistics in prettier form (use once for powers of 10, twice for powers of 2)&lt;br /&gt;
* &amp;lt;code&amp;gt;--progress&amp;lt;/code&amp;gt;: show progress of each file transferred, implies &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;-n&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;--dry-run&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[http://rsync.samba.org/ftp/rsync/rsync.html rsync&#039;s full manpage]&lt;br /&gt;
&lt;br /&gt;
rsync&#039;s advantages:&lt;br /&gt;
* like cp, can handle ACLs and xattrs; many tar and cpio implementations don&#039;t&lt;br /&gt;
* like cpio, can optionally work over the network&lt;br /&gt;
* can resume incomplete transfers, and can do incremental updates if the data is being copied multiple times&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Including/excluding from transfers:&lt;br /&gt;
* &amp;lt;code&amp;gt;--include=&amp;lt;var&amp;gt;pattern&amp;lt;/var&amp;gt;[/]&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;--exclude=&amp;lt;var&amp;gt;pattern&amp;lt;/var&amp;gt;[/]&amp;lt;/code&amp;gt;&lt;br /&gt;
Each of these may be repeated. The &amp;lt;var&amp;gt;pattern&amp;lt;/var&amp;gt;s may contain &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;**&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[a-z]&amp;lt;/code&amp;gt;.&lt;br /&gt;
A trailing &amp;lt;code&amp;gt;&amp;lt;var&amp;gt;dir&amp;lt;/var&amp;gt;/***&amp;lt;/code&amp;gt; matches both &amp;lt;var&amp;gt;dir&amp;lt;/var&amp;gt; and its contents.&lt;br /&gt;
If &amp;lt;var&amp;gt;pattern&amp;lt;/var&amp;gt; contains a &amp;lt;code&amp;gt;**&amp;lt;/code&amp;gt; or (non-trailing) &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt;, it matches against the full path from {{Path|/target}}, else it only matches against the final path element.&lt;br /&gt;
&lt;br /&gt;
=== lvm ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;This is one reason I like LVM. Just add the new disk to the volume group, pvmove the logical volumes from the old to new disk, [wait a bit], remove the old disk from the volume group, and then from the system. If it&#039;s your boot disk you&#039;re replacing then you also need to update your boot loader.&amp;quot; &amp;lt;!-- http://superuser.com/a/11468/28187 --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See [[Setting up Logical Volumes with LVM]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Other tools ===&lt;br /&gt;
&lt;br /&gt;
{{Cmd|cd /source&lt;br /&gt;
pax -pe -rw -v [-X] -YZ . /target}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Installation]]&lt;br /&gt;
[[Category:Storage]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Create_UEFI_boot_USB&amp;diff=15242</id>
		<title>Create UEFI boot USB</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Create_UEFI_boot_USB&amp;diff=15242"/>
		<updated>2018-04-29T19:18:56Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: Fix up command blocks&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This article explains how to create an UEFI boot USB with parted and gummiboot.&lt;br /&gt;
&lt;br /&gt;
In this example we will use {{Path|/dev/sdX}}. This will be different depending on your system.&lt;br /&gt;
&lt;br /&gt;
== Create GPT boot partition ==&lt;br /&gt;
&lt;br /&gt;
Install {{Pkg|parted}}&lt;br /&gt;
{{Cmd | apk add parted }}&lt;br /&gt;
&lt;br /&gt;
Create a single UEFI boot partitions.&lt;br /&gt;
{{warning| this will erase all content of your {{Path|/dev/sdX}}. Make sure that you use correct device}}&lt;br /&gt;
&lt;br /&gt;
{{Cmd | parted --script /dev/sdX mklabel gpt&lt;br /&gt;
 parted --script --align{{=}}optimal /dev/sdX mkpart ESP fat32 1MiB 512MiB&lt;br /&gt;
 parted --script /dev/sdX set 1 boot on }}&lt;br /&gt;
&lt;br /&gt;
== Create fat32 filesystem ==&lt;br /&gt;
&lt;br /&gt;
Create a fat32 system with the name `Alpine`.&lt;br /&gt;
&lt;br /&gt;
{{Cmd | mkfs.vfat -n Alpine /dev/sdX1 }}&lt;br /&gt;
&lt;br /&gt;
== Copy content of ISO image to filesystem ==&lt;br /&gt;
&lt;br /&gt;
It is possible to mount the iso image and copy files with {{codeline|cp}} or {{codeline|rsync}} and it is also possible to use {{codeline|7z}} to extract content from the iso. In this example I will use the {{codeline|uniso}} utility from {{Pkg|alpine-conf}} package.&lt;br /&gt;
&lt;br /&gt;
{{Cmd | mount -t vfat /dev/sdX1 /mnt&lt;br /&gt;
 cd /mnt &amp;amp;&amp;amp; uniso &amp;lt; /path/to/alpine-3.4.0-x86_64.iso }}&lt;br /&gt;
&lt;br /&gt;
== Copy gummiboot efi binary ==&lt;br /&gt;
&lt;br /&gt;
{{note| Gummiboot has been forked in Alpine Linux since it has been [https://www.freedesktop.org/wiki/Software/systemd/systemd-boot/ consumed by systemd upstream].}}&lt;br /&gt;
&lt;br /&gt;
UEFI will look for a {{Path|EFI/bootx64.efi}} as a fallback efi loader. We copy {{Path|gummibootx64.efi}} to this location.&lt;br /&gt;
&lt;br /&gt;
{{Cmd | mkdir -p /mnt/EFI/Boot&lt;br /&gt;
 apk add gummiboot&lt;br /&gt;
 cp /usr/lib/gummiboot/gummibootx64.efi /mnt/EFI/Boot/bootx64.efi }}&lt;br /&gt;
&lt;br /&gt;
== Create configuration files for boot loader ==&lt;br /&gt;
&lt;br /&gt;
We need create some configuration files for gummiboot.&lt;br /&gt;
{{Cmd | mkdir -p loader/entries }}&lt;br /&gt;
&lt;br /&gt;
{{Cat | loader/loader.conf |default alpine&lt;br /&gt;
timeout 4&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
The options are taken from {{Path|boot/syslinux/syslinux.cfg}}&lt;br /&gt;
&lt;br /&gt;
{{Cat | loader/entries/alpine.conf |title    Alpine Linux&lt;br /&gt;
linux    /boot/vmlinuz-hardened&lt;br /&gt;
initrd   /boot/initramfs-hardened&lt;br /&gt;
options  modloop{{=}}/boot/modloop-hardened modules{{=}}loop,squashfs,sd-mod,usb-storage quiet&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Finally umount the disk&lt;br /&gt;
{{Cmd | cd ~ &amp;amp;&amp;amp; umount /mnt}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Installation]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=How_to_setup_a_Alpine_Linux_mirror&amp;diff=14261</id>
		<title>How to setup a Alpine Linux mirror</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=How_to_setup_a_Alpine_Linux_mirror&amp;diff=14261"/>
		<updated>2018-01-03T16:12:41Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This document describes how to set up an Alpine Linux mirror and make it available via http and rsync.&lt;br /&gt;
&lt;br /&gt;
We will:&lt;br /&gt;
* create the dir where we have the mirror&lt;br /&gt;
* set up a cron job to sync with master mirror every hour&lt;br /&gt;
* set up lighttpd for http access&lt;br /&gt;
* set up rsync so other mirrors can rsync from you&lt;br /&gt;
&lt;br /&gt;
Make sure that you have enough disk space; each v3.x branch has around 20 GiB.&lt;br /&gt;
&lt;br /&gt;
Current (2018-01-03) disk usage:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!edge&lt;br /&gt;
!v2.4&lt;br /&gt;
!v2.5&lt;br /&gt;
!v2.6&lt;br /&gt;
!v2.7&lt;br /&gt;
!v3.0&lt;br /&gt;
!v3.1&lt;br /&gt;
!v3.2&lt;br /&gt;
!v3.3&lt;br /&gt;
!v3.4&lt;br /&gt;
!v3.5&lt;br /&gt;
!v3.6&lt;br /&gt;
!v3.7&lt;br /&gt;
!Total&lt;br /&gt;
|-&lt;br /&gt;
|71.3G        &lt;br /&gt;
|18.8G   &lt;br /&gt;
|10.4G   &lt;br /&gt;
|13.0G   &lt;br /&gt;
|16.5G   &lt;br /&gt;
|16.5G   &lt;br /&gt;
|17.5G   &lt;br /&gt;
|14.5G   &lt;br /&gt;
|19.0G   &lt;br /&gt;
|23.2G   &lt;br /&gt;
|32.5G   &lt;br /&gt;
|34.4G&lt;br /&gt;
|71.3G&lt;br /&gt;
|&#039;&#039;&#039;358.9G&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Setting up the cron job ==&lt;br /&gt;
Install rsync which will be used to sync from the master mirror.&lt;br /&gt;
{{Cmd|apk add rsync}}&lt;br /&gt;
&lt;br /&gt;
Save the following file as &#039;&#039;/etc/periodic/hourly/alpine-mirror&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
# make sure we never run 2 rsync at the same time&lt;br /&gt;
lockfile=&amp;quot;/tmp/alpine-mirror.lock&amp;quot;&lt;br /&gt;
if [ -z &amp;quot;$flock&amp;quot; ] ; then&lt;br /&gt;
  exec env flock=1 flock -n $lockfile &amp;quot;$0&amp;quot; &amp;quot;$@&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
src=rsync://rsync.alpinelinux.org/alpine/ &lt;br /&gt;
dest=/var/www/localhost/htdocs/alpine/&lt;br /&gt;
&lt;br /&gt;
# uncomment this to exclude old v2.x branches&lt;br /&gt;
#exclude=&amp;quot;--exclude v2.*&amp;quot;&lt;br /&gt;
&lt;br /&gt;
mkdir -p &amp;quot;$dest&amp;quot;&lt;br /&gt;
/usr/bin/rsync \&lt;br /&gt;
        --archive \&lt;br /&gt;
        --update \&lt;br /&gt;
        --hard-links \&lt;br /&gt;
        --delete \&lt;br /&gt;
        --delete-after \&lt;br /&gt;
        --delay-updates \&lt;br /&gt;
        --timeout=600 \&lt;br /&gt;
        $exclude \&lt;br /&gt;
        &amp;quot;$src&amp;quot; &amp;quot;$dest&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(or use [https://gist.github.com/jirutka/288c6fff7c0b8a835d143686207316be this script])&lt;br /&gt;
&lt;br /&gt;
Make it executable:&lt;br /&gt;
{{Cmd|&amp;lt;nowiki&amp;gt;chmod +x /etc/periodic/hourly/alpine-mirror&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
Now it will sync every hour. (given cron runs)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Setting up HTTP access via lighttpd ==&lt;br /&gt;
&lt;br /&gt;
Install the lighttpd server&lt;br /&gt;
{{Cmd|apk add lighttpd}}&lt;br /&gt;
&lt;br /&gt;
Enable dir listings by uncommenting the following line in &#039;&#039;/etc/lighttpd/lighttpd.conf&#039;&#039;:&lt;br /&gt;
 dir-listing.activate      = &amp;quot;enable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Also set cache-control to force cache revalidate every 30 mins. Uncomment mod_setenv in &#039;&#039;/etc/lighttpd/lighttpd.conf&#039;&#039;:&lt;br /&gt;
 &amp;quot;mod_setenv&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
Add also the following lines to &#039;&#039;/etc/lighttpd/lighttpd.conf&#039;&#039;:&lt;br /&gt;
 setenv.add-response-header += (           &lt;br /&gt;
         &amp;quot;Cache-Control&amp;quot; =&amp;gt; &amp;quot;must-revalidate&amp;quot;&lt;br /&gt;
 )&lt;br /&gt;
&lt;br /&gt;
Start lighttpd and make it start at boot:&lt;br /&gt;
{{Cmd|rc-service lighttpd start&lt;br /&gt;
rc-update add lighttpd}}&lt;br /&gt;
&lt;br /&gt;
{{Note|You may wish to consider [[Darkhttpd]] as an alternative to [[Lighttpd]]&lt;br /&gt;
&lt;br /&gt;
If so, simply install, start and auto-start the webserver:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|apk add darkhttpd &amp;amp;&amp;amp; rc-service darkhttpd start &amp;amp;&amp;amp; rc-update add darkhttpd}}&lt;br /&gt;
&lt;br /&gt;
Darkhttpd will, by default, offer directory listings and serve data from /var/www/localhost/htdocs/ &lt;br /&gt;
&lt;br /&gt;
See the main article on [[Darkhttpd]] for more configuration options}}&lt;br /&gt;
&lt;br /&gt;
== Setting up rsyncd ==&lt;br /&gt;
Add the following lines to &#039;&#039;/etc/rsyncd.conf&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[alpine]&lt;br /&gt;
        path = /var/www/localhost/htdocs/alpine&lt;br /&gt;
        comment = My Alpine Linux Mirror&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optionally set a bandwidth limit in &#039;&#039;/etc/conf.d/rsyncd&#039;&#039;. In this example we limit to 500Kbytes/s (approx 5Mbit/s)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSYNC_OPTS=&amp;quot;--bwlimit=500&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Mirror statistics ==&lt;br /&gt;
&lt;br /&gt;
Simple bandwidth statistics can be generated with vnstat.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|apk add vnstat}}&lt;br /&gt;
&lt;br /&gt;
edit /etc/vnstat.conf and replace the interface name with the appropriate one.&lt;br /&gt;
&lt;br /&gt;
Start vnstatd&lt;br /&gt;
&lt;br /&gt;
{{Cmd|/etc/init.d/vnstatd start }}&lt;br /&gt;
&lt;br /&gt;
copy the following script to /etc/periodic/15min/stats and make sure your crond is running.&lt;br /&gt;
please not that heredoc should be tab indented or the script will fail. A working copy can be found here: http://tpaste.us/RrMv&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
output=&amp;quot;/var/www/localhost/htdocs/.stats&amp;quot;&lt;br /&gt;
nic=&amp;quot;eth0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
generate_index() {&lt;br /&gt;
    cat &amp;lt;&amp;lt;-EOF&lt;br /&gt;
    &amp;lt;!doctype html&amp;gt;&lt;br /&gt;
    &amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;head&amp;gt;&lt;br /&gt;
        &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;meta http-equiv=&amp;quot;cache-control&amp;quot; content=no-cache&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;meta http-equiv=&amp;quot;refresh&amp;quot; content=&amp;quot;3000&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;title&amp;gt;Alpine Linux mirror statistics&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;/head&amp;gt;&lt;br /&gt;
    &amp;lt;body&amp;gt;&lt;br /&gt;
        &amp;lt;table border=&amp;quot;0&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;summary.png&amp;quot; alt=&amp;quot;summary&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;hours.png&amp;quot; alt=&amp;quot;hours&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
            &amp;lt;tr&amp;gt;&amp;lt;td rowspan=&amp;quot;2&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;days.png&amp;quot; alt=&amp;quot;days&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;top10.png&amp;quot; alt=&amp;quot;top10&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;img src=&amp;quot;months.png&amp;quot; alt=&amp;quot;months&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
        &amp;lt;/table&amp;gt;&lt;br /&gt;
    &amp;lt;/body&amp;gt;&lt;br /&gt;
    &amp;lt;/html&amp;gt;&lt;br /&gt;
    EOF&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if  [ ! -f &amp;quot;$output&amp;quot;/index.html ]; then&lt;br /&gt;
    mkdir -p $output&lt;br /&gt;
    generate_index &amp;gt; &amp;quot;$output&amp;quot;/index.html&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
for type in hours days months top10 summary hsummary vsummary; do&lt;br /&gt;
    vnstati --${type} -i $nic -o $output/${type}.png&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Update mirror from mqtt ==&lt;br /&gt;
&lt;br /&gt;
If you want your mirror to be really uptodate compared to our master mirror you can subscribe to Alpine Linux message server &amp;quot;msg.alpinelinux.org&amp;quot; and check for upload messages.&lt;br /&gt;
Add mqtt-exec to be able to execute processes when specific topics are being send.&lt;br /&gt;
&lt;br /&gt;
{{Cmd| apk add mqtt-exec}}&lt;br /&gt;
&lt;br /&gt;
mqtt-exec supports running multiple time so we need to setup a specific config.&lt;br /&gt;
&lt;br /&gt;
{{Cmd| ln -s /etc/init.d/mqtt-exec /etc/init.d/mqtt-exec.sync-mirror}}&lt;br /&gt;
&lt;br /&gt;
{{Cmd| ln -s /etc/conf.d/mqtt-exec /etc/conf.d/mqtt-exec.sync-mirror}}&lt;br /&gt;
&lt;br /&gt;
edit /etc/conf.d/mqtt-exec.sync-mirror&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mqtt_topics=&amp;quot;rsync/rsync.alpinelinux.org/#&amp;quot;&lt;br /&gt;
exec_user=&amp;quot;buildozer&amp;quot;&lt;br /&gt;
exec_command=&amp;quot;/usr/local/bin/sync-mirror&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Copy the following file to /usr/local/bin/sync-mirror and make it executable (dont forget to update the variables).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
src=&amp;quot;rsync://rsync.alpinelinux.org/alpine/&amp;quot;&lt;br /&gt;
dest=&amp;quot;/var/www/localhost/htdocs/alpine/&amp;quot;&lt;br /&gt;
lock=&amp;quot;/tmp/sync-mirror.lock&amp;quot;&lt;br /&gt;
topic=&amp;quot;$1&amp;quot;&lt;br /&gt;
dir=&amp;quot;$2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[ -z &amp;quot;$flock&amp;quot; ] &amp;amp;&amp;amp; exec env flock=1 flock $lock $0 &amp;quot;$@&amp;quot;&lt;br /&gt;
&lt;br /&gt;
if [ -n &amp;quot;$dir&amp;quot; ] &amp;amp;&amp;amp; [ -d &amp;quot;$dest/${dir%/*}&amp;quot; ]; then&lt;br /&gt;
    logger &amp;quot;Syncing directory: $dir&amp;quot;&lt;br /&gt;
    src=&amp;quot;${src}${dir%/}/&amp;quot;&lt;br /&gt;
    dest=&amp;quot;${dest}${dir%/}/&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
    logger &amp;quot;Syncing all directories&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
/usr/bin/rsync \&lt;br /&gt;
    --archive \&lt;br /&gt;
    --update \&lt;br /&gt;
    --verbose \&lt;br /&gt;
    --progress \&lt;br /&gt;
    --timeout=600 \&lt;br /&gt;
    --delay-updates \&lt;br /&gt;
    --delete-after \&lt;br /&gt;
    &amp;quot;$src&amp;quot; \&lt;br /&gt;
    &amp;quot;$dest&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And finally start mqtt-exec and let it listen on msg.alpinelinux.org&lt;br /&gt;
&lt;br /&gt;
{{Cmd|/etc/init.d/mqtt-exec.sync-mirror start}}&lt;br /&gt;
&lt;br /&gt;
To make sure you are not missing any packages (in case something goes wrong with MQTT subscription) you can periodically sync all directories by adding the script to cron.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|ln -s /usr/local/bin/sync-mirror /etc/periodic/hourly/sync-mirror}}&lt;br /&gt;
&lt;br /&gt;
Now watch your syslog as it should tell you when it will update directories in your local mirror.&lt;br /&gt;
&lt;br /&gt;
[[Category:Server]]&lt;br /&gt;
[[Category:Package Manager]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=APKBUILD_Reference&amp;diff=14241</id>
		<title>APKBUILD Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=APKBUILD_Reference&amp;diff=14241"/>
		<updated>2017-12-29T04:21:19Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;APKBUILDs are the scripts that are created in order to build Alpine packages using the [[abuild]] tool.&lt;br /&gt;
&lt;br /&gt;
See [[aports]] for details on Alpine&#039;s official ports repository.&lt;br /&gt;
&lt;br /&gt;
This page is intended to serve as a reference for creating APKBUILDs; if this is your first time creating a package for Alpine Linux, please see [[Creating an Alpine package]].&lt;br /&gt;
&lt;br /&gt;
= Legend =&lt;br /&gt;
The following notes will assist you in understanding this document.&lt;br /&gt;
&lt;br /&gt;
In description text:&lt;br /&gt;
* If a variable is not prefixed with a &#039;&#039;$&#039;&#039;, it will be represented by italics (i.e., &#039;&#039;srcdir&#039;&#039; ).&lt;br /&gt;
* Functions will also be represented by italics, but will also end with a pair of parentheses (i.e., &#039;&#039;build()&#039;&#039; ).&lt;br /&gt;
* Shell commands will be represented &amp;lt;code&amp;gt;like this&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Variables =&lt;br /&gt;
{{Note|Variables that contain a path (e.g. &#039;&#039;$srcdir&#039;&#039; and &#039;&#039;$pkgdir&#039;&#039;) should always be quoted using double quotes (i.e., &#039;&#039;&amp;quot;$srcdir&amp;quot;&#039;&#039;).  This is done to prevent things from breaking, should the user have the APKBUILD in a directory path that contains spaces.}}&lt;br /&gt;
{{Note|All arbitrary variable and function names should be prefixed with an underscore character ( _ ) to avoid name clashes with the internals of abuild (for example, &#039;&#039;_luaversions&#039;&#039;).}}&lt;br /&gt;
&lt;br /&gt;
== abuild-defined variables ==&lt;br /&gt;
The following variables are defined by abuild:&lt;br /&gt;
&lt;br /&gt;
==== startdir ====&lt;br /&gt;
: The directory where the APKBUILD script is.&lt;br /&gt;
==== srcdir ====&lt;br /&gt;
: The directory where sources, from the &#039;&#039;source&#039;&#039; variable, are downloaded to and unpacked to.&lt;br /&gt;
==== pkgdir ====&lt;br /&gt;
: This directory should receive the files for the main package.  For example, a normal [http://en.wikipedia.org/wiki/GNU_build_system autotools] package would have &amp;lt;code&amp;gt;make DESTDIR=&amp;quot;$pkgdir&amp;quot; install&amp;lt;/code&amp;gt; in the &#039;&#039;package()&#039;&#039; function.&lt;br /&gt;
==== subpkgdir ====&lt;br /&gt;
: This directory should receive the files for a subpackage. This variable should only be used from subpackage functions.&lt;br /&gt;
==== builddir ====&lt;br /&gt;
: This variable should point to the directory inside the &#039;&#039;srcdir&#039;&#039; where the main package source is unpacked.  This is typically &#039;&#039;$srcdir/$pkgname-$pkgver&#039;&#039;.  It’s used by the default &#039;&#039;prepare()&#039;&#039; function as a working directory when applying patches.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== User-defined variables ==&lt;br /&gt;
The following variables should be defined by the user:&lt;br /&gt;
==== arch ====&lt;br /&gt;
: Package architecture(s) to build for.  Can be one of: &#039;&#039;&#039;[[x86]], [[x86_64]], [[armhf]], [[aarch64]], [[ppc64le]], [[s390x]], all&#039;&#039;&#039;, or &#039;&#039;&#039;noarch&#039;&#039;&#039;, where &#039;&#039;&#039;all&#039;&#039;&#039; means all architectures, and &#039;&#039;&#039;noarch&#039;&#039;&#039; means it&#039;s architecture-independent (e.g., a pure-python package).&lt;br /&gt;
: {{Tip|To determine if your APKBUILD can use &#039;&#039;&#039;noarch&#039;&#039;&#039;: First specify &#039;&#039;&#039;all&#039;&#039;&#039; and then build the package by executing &amp;lt;code&amp;gt;abuild -r&amp;lt;/code&amp;gt;.  Watch the output towards the end for warnings saying that &#039;&#039;&#039;noarch&#039;&#039;&#039; can be used.  If the main package and all subpackages, if you have any subpackages, give a warning saying that &#039;&#039;&#039;noarch&#039;&#039;&#039; can be used, then you can use &#039;&#039;&#039;noarch&#039;&#039;&#039;.}}&lt;br /&gt;
&lt;br /&gt;
==== depends ====&lt;br /&gt;
: Run-time dependency package(s) that are not shared-object dependencies.  Shared objects dependencies are auto-detected and should not be specified here.&lt;br /&gt;
==== depends_dev ====&lt;br /&gt;
: Run-time dependency package(s) for the &#039;&#039;&#039;$pkgname-dev&#039;&#039;&#039; subpackage.&lt;br /&gt;
&lt;br /&gt;
: {{Note|From ncopa on IRC: To find out if you need to add a package to depends_dev have a look at *requires* in usr/lib/pkgconfig/*.pc. With libtool it gets more complicated, but we should delete the .la files. Also check if there are any  /usr/bin/*-configure #!/bin/bash #!/usr/bin/perl or Python. Sometimes scripts or similar are generated at build time (i.e autoconf automake) then you normally don&#039;t need add those to depends_dev. You can also just add all -dev makedepends to depends_dev but it will slow the build process a little bit (more build dependencies).}}&lt;br /&gt;
==== giturl ====&lt;br /&gt;
:Git repository from which &amp;lt;code&amp;gt;abuild checkout&amp;lt;/code&amp;gt; checks out. You can checkout a specific branch in git by adding &amp;lt;code&amp;gt;-b $branch&amp;lt;/code&amp;gt;.&lt;br /&gt;
==== install ====&lt;br /&gt;
: There are 6 different types of install scripts.  Install scripts are named &#039;&#039;&#039;$pkgname.action&#039;&#039;&#039;, where &#039;&#039;&#039;action&#039;&#039;&#039; can be:  &#039;&#039;&#039;pre-install, post-install, pre-upgrade, post-upgrade, pre-deinstall&#039;&#039;&#039;, or &#039;&#039;&#039;post-deinstall&#039;&#039;&#039;.  For example, if &#039;&#039;pkgname&#039;&#039; is set to &#039;&#039;&#039;mypackage&#039;&#039;&#039; and &#039;&#039;install&#039;&#039; is set to &#039;&#039;&#039;$pkgname.post-install&#039;&#039;&#039;, then a script named &#039;&#039;&#039;mypackage.post-install&#039;&#039;&#039; must exist along-side the APKBUILD.&lt;br /&gt;
&lt;br /&gt;
: First, a few notes regarding install scripts:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;{{Note|When using install scripts, &#039;&#039;$install&#039;&#039; should be included in &#039;&#039;source&#039;&#039; so that checksums can be generated and used for the install scripts specified in &#039;&#039;install&#039;&#039;.  For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
install=&amp;quot;$pkgname.pre-install $pkgname.post-install&amp;quot;&lt;br /&gt;
source=&amp;quot;http://....&lt;br /&gt;
       $install&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;}}&lt;br /&gt;
{{Note|Always use &amp;lt;code&amp;gt;/bin/sh&amp;lt;/code&amp;gt; for the command-line interpreter on the [http://en.wikipedia.org/wiki/Shebang_%28Unix%29 shebang line] of your install scripts.}}&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following are the different types of install scripts in detail:&lt;br /&gt;
&lt;br /&gt;
===== $pkgname.pre-install =====&lt;br /&gt;
: This script is executed &#039;&#039;before installing&#039;&#039; the package.  Typical use is when the package needs a group and a user to be created. For example:&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
&lt;br /&gt;
addgroup -S clamav 2&amp;gt;/dev/null&lt;br /&gt;
adduser -S -D -H -s /bin/false -G clamav -g clamav clamav 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
{{Note|If the script exits with a failure (e.g., if the user already exists), the package will not be installed and &amp;lt;code&amp;gt;apk&amp;lt;/code&amp;gt; will exit with failure, hence the &amp;lt;code&amp;gt;exit 0&amp;lt;/code&amp;gt; at the end.}}&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== $pkgname.post-install =====&lt;br /&gt;
: This script is executed &#039;&#039;after installing&#039;&#039; the package.&lt;br /&gt;
&lt;br /&gt;
===== $pkgname.pre-upgrade =====&lt;br /&gt;
: This script is executed &#039;&#039;before upgrading/downgrading/reinstalling&#039;&#039; the package. Note that exiting with failure will not cause apk to exit with failure, but will mark the package as broken.&lt;br /&gt;
&lt;br /&gt;
===== $pkgname.post-upgrade =====&lt;br /&gt;
: This script is executed &#039;&#039;after upgrading/downgrading/reinstalling&#039;&#039; the package.&lt;br /&gt;
&lt;br /&gt;
===== $pkgname.pre-deinstall =====&lt;br /&gt;
: This script is executed &#039;&#039;before uninstalling&#039;&#039; the package.&lt;br /&gt;
: {{Note|If the script exits with failure, &amp;lt;code&amp;gt;apk&amp;lt;/code&amp;gt; will not uninstall the package.}}&lt;br /&gt;
&lt;br /&gt;
===== $pkgname.post-deinstall =====&lt;br /&gt;
: This script is executed &#039;&#039;after uninstalling&#039;&#039; the package.&lt;br /&gt;
&lt;br /&gt;
==== install_if ====&lt;br /&gt;
:install_if can be used when a package needs to be installed when some packages are already installed or are in the dependency tree. It works in reverse to the &#039;&#039;recommends&#039;&#039; feature, that other package managers provide.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;Example:&#039;&#039;&#039; When package &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; has &amp;lt;code&amp;gt;install_if=&amp;quot;B C&amp;quot;&amp;lt;/code&amp;gt;, and the user runs &amp;lt;code&amp;gt;apk add B C&amp;lt;/code&amp;gt;, then package &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt; will get automatically installed.&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;Example 2:&#039;&#039;&#039; A real use-case in Alpine is open-vm-tools. Currently it contains the userspace tools and separate packages for the kernel modules (grsec and vserver). When we install the userspace tools, apk should automatically install the correct kernel modules and will need to figure out for which kernel. This is where install_if jumps in. For any of the kernel modules package we would use:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;pre&amp;gt;install_if=&amp;quot;linux-${_flavor}=${_kernelver} open-vm-tools&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:This will automatically install the package when the specified packages are installed or are in dependency tree.&lt;br /&gt;
&lt;br /&gt;
==== license ====&lt;br /&gt;
: License(s) for the package, for example &amp;lt;code&amp;gt;GPL3+&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;BSD&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;MIT&amp;lt;/code&amp;gt; [[Creating_an_Alpine_package#license|(details)]].&lt;br /&gt;
&lt;br /&gt;
==== makedepends ====&lt;br /&gt;
: Build-time dependency package(s).&lt;br /&gt;
==== md5sums/sha256sums/sha512sums ====&lt;br /&gt;
: Checksums for the files/URLs listed in &#039;&#039;source&#039;&#039;.  The checksums are normally generated and updated by executing &amp;lt;code&amp;gt;abuild checksum&amp;lt;/code&amp;gt; and should be the last item in the APKBUILD.&lt;br /&gt;
&lt;br /&gt;
New packages should prefer sha512sums and avoid md5sums.&lt;br /&gt;
==== options ====&lt;br /&gt;
: Build-time options for the package.&lt;br /&gt;
&lt;br /&gt;
: {| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Option&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!archcheck&amp;lt;/code&amp;gt;&lt;br /&gt;
| Do not try to verify that the architecture of the binary files is the same architecture as abuild should build for. One example where it makes sense to set this are packages with firmware files, that get executed on another CPU (such as WiFi firmware).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!check&amp;lt;/code&amp;gt;&lt;br /&gt;
| Do not try to run the &amp;lt;code&amp;gt;check()&amp;lt;/code&amp;gt; function. Please always add a short comment after the &amp;lt;code&amp;gt;!check&amp;lt;/code&amp;gt; about why it&#039;s disabled. [https://github.com/alpinelinux/aports/pull/2322#discussion_r142545300] Creating a very simple check function, that calls &amp;lt;code&amp;gt;program --version&amp;lt;/code&amp;gt; is better than disabling tests completely. [https://github.com/alpinelinux/aports/pull/2322#discussion_r142543002]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!strip&amp;lt;/code&amp;gt;&lt;br /&gt;
| Avoid stripping symbols from binaries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;suid&amp;lt;/code&amp;gt;&lt;br /&gt;
| Allow [https://en.wikipedia.org/wiki/Setuid setuid] binaries.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!tracedeps&amp;lt;/code&amp;gt;&lt;br /&gt;
| Do not automatically find dependencies (e.g. by using &amp;lt;code&amp;gt;ldd&amp;lt;/code&amp;gt; to find dynamic libraries, which the resulting binary links against).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== pkgdesc ====&lt;br /&gt;
: A brief, one-line description of what the package does.&lt;br /&gt;
&lt;br /&gt;
: Here&#039;s an example from the OpenSSH client package:&lt;br /&gt;
: &amp;lt;pre&amp;gt;pkgdesc=&amp;quot;Port of OpenBSD&#039;s free SSH release - client&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
==== pkggroups ====&lt;br /&gt;
: System group(s) to be created during build-time.  System group(s) should also be created in the &#039;&#039;&#039;[[APKBUILD Reference#.24pkgname.pre-install|$pkgname.pre-install]]&#039;&#039;&#039; script, so that the system group(s) are also created prior to package installation for run-time use.&lt;br /&gt;
==== pkgname ====&lt;br /&gt;
: The name of the package.  All letters should be lowercase.&lt;br /&gt;
: {{Note|When creating an APKBUILD of a module or library for another package, we use some common package prefixes, such as: &#039;&#039;lua-&#039;&#039;, &#039;&#039;perl-&#039;&#039;, &#039;&#039;php-&#039;&#039;, and &#039;&#039;py-&#039;&#039;.  Search aports for other common prefixes.}}&lt;br /&gt;
&lt;br /&gt;
==== pkgrel ====&lt;br /&gt;
: Alpine package release number.  Starts at 0 (zero).  Always increment &#039;&#039;pkgrel&#039;&#039; when making updates to an aport; reset &#039;&#039;pkgrel&#039;&#039; to 0 (zero) when incrementing &#039;&#039;pkgver&#039;&#039;.&lt;br /&gt;
==== pkgusers ====&lt;br /&gt;
: System user(s) to be created during build-time.  System user(s) should also be created in the &#039;&#039;&#039;[[APKBUILD Reference#.24pkgname.pre-install|$pkgname.pre-install]]&#039;&#039;&#039; script, so that the system user(s) are also created prior to package installation for run-time use.&lt;br /&gt;
==== pkgver ====&lt;br /&gt;
: The version of the software being packaged.&lt;br /&gt;
==== provides ====&lt;br /&gt;
: List of package names (and optionally version info) this package provides.&lt;br /&gt;
&lt;br /&gt;
: If package with a version is provided (provides=&#039;foo=1.2&#039;) apk will consider it as an alternate name and it will automatically consider the package for installation by the alternate name, and conflict with other packages having the same name, or provides.&lt;br /&gt;
&lt;br /&gt;
: If version is not provided (provides=&#039;foo&#039;), apk will consider it as virtual package name. Several package with same non-versioned provides can be installed simultaneously. However, none of them will be installed by default when requested by the virtual name - instead, error message is given and user is asked to choose which package providing the virtual name should be installed.&lt;br /&gt;
==== replaces ====&lt;br /&gt;
: Package(s) that this package replaces.  This package will &amp;quot;take over&amp;quot; files owned by packages listed in the &#039;&#039;replaces&#039;&#039; variable.  This is useful when files move from one package to another, or when a package gets renamed.&lt;br /&gt;
==== replaces_priority ====&lt;br /&gt;
: The priority of the replaces. If multiple packages replace each other, then will the package with highest &#039;&#039;replaces_priority&#039;&#039; win.&lt;br /&gt;
==== source ====&lt;br /&gt;
: The source variable is not only used to list the remote source files to fetch, it is also used to list the local files that abuild will need in order to build the apk. Examples of such local files include: init.d files, conf.d files, install files (see [[APKBUILD Reference#install|install variable]]), patches, and all other necessary files.&lt;br /&gt;
&lt;br /&gt;
: Here are few things to note:&lt;br /&gt;
&lt;br /&gt;
:* When you are finished adding local and/or remote files to &#039;&#039;source&#039;&#039;, you can execute the following command to add their checksums to the APKBUILD file:&lt;br /&gt;
:: {{Cmd|abuild checksum}}&lt;br /&gt;
:: {{Note|When later updating the content of &#039;&#039;source&#039;&#039;, or updating a file that is listed in &#039;&#039;source&#039;&#039;, you must also update their checksums again with the same command.}}&lt;br /&gt;
&lt;br /&gt;
:* When the remote file is hosted at SourceForge, it&#039;s best to specify the special mirrors link used by SourceForge:&lt;br /&gt;
:: &amp;lt;pre&amp;gt;http://downloads.sourceforge.net/$pkgname/$pkgname-$pkgver.tar.gz&amp;lt;/pre&amp;gt;&lt;br /&gt;
:: (or similar depending on the package).&lt;br /&gt;
&lt;br /&gt;
:* You can set target filename (eg &#039;save as...&#039;) by prefixing the URI with &#039;&#039;filename::&#039;&#039;. This is useful when the remote filename is not specified in the URI (ie, does not end in &#039;/software-1.0.tar.gz&#039;), such as:&lt;br /&gt;
:: &amp;lt;pre&amp;gt;http://oss.example.org/?get=software&amp;amp;ver=1.0&amp;lt;/pre&amp;gt;&lt;br /&gt;
:: or when the filename is braindead, like githubs&#039; download tags:&lt;br /&gt;
:: &amp;lt;pre&amp;gt;https://github.com/software/software/archive/v$pkgver.tar.gz&amp;lt;/pre&amp;gt;&lt;br /&gt;
:: The above two examples needs a target filename prefix:&lt;br /&gt;
:: &amp;lt;pre&amp;gt;$pkgname-$pkgver.tar.gz::http://oss.example.org/?get=software&amp;amp;ver=$pkgver&amp;lt;/pre&amp;gt;&lt;br /&gt;
:: and:&lt;br /&gt;
:: &amp;lt;pre&amp;gt;$pkgname-$pkgver.tar.gz::https://github.com/software/software/archive/v$pkgver.tar.gz&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:* abuild currently supports the following protocols for remote file retrieval:&lt;br /&gt;
:** http&lt;br /&gt;
:** https&lt;br /&gt;
:** ftp&lt;br /&gt;
&lt;br /&gt;
:* abuild currently supports the following archive types/archive file extensions:&lt;br /&gt;
:** .tar.gz / .tgz&lt;br /&gt;
:** .tar.bz2&lt;br /&gt;
:** .tar.lzma&lt;br /&gt;
:** .tar.xz&lt;br /&gt;
:** .zip&lt;br /&gt;
&lt;br /&gt;
:: {{Note|Legacy APKBUILD scripts define &#039;&#039;source&#039;&#039; variable as &amp;quot;saveas-[brain-dead-url]/[target-filename]&amp;quot; format instead of the modern [target-filename]::[brain-dead-url].&amp;lt;br /&amp;gt;&#039;&#039;BAD&#039;&#039;:   source&amp;amp;#61;&amp;quot;saveas-http://releases.ddvtech.com/download.php?pack&amp;amp;#61;libmist_dist&amp;amp;ver&amp;amp;#61;RC/$pkgname-$pkgver.tar.gz&amp;quot;&amp;lt;br /&amp;gt;&#039;&#039;GOOD&#039;&#039;:   source&amp;amp;#61;$pkgname-$pkgver.tar.gz::http://releases.ddvtech.com/download.php?pack&amp;amp;#61;libmist_dist&amp;amp;ver&amp;amp;#61;RC&amp;quot;}}&lt;br /&gt;
&lt;br /&gt;
==== subpackages ====&lt;br /&gt;
: Subpackages built from this APKBUILD.  abuild will parse this variable and try to find a subpackage split function.  The split function must &#039;&#039;move&#039;&#039; files that do not belong in the main package, from &#039;&#039;$pkgdir&#039;&#039; to &#039;&#039;$subpkgdir&#039;&#039;.  Files and directories can also be &#039;&#039;copied&#039;&#039; from &#039;&#039;$startdir&#039;&#039; and &#039;&#039;$srcdir&#039;&#039; to &#039;&#039;$subpkgdir&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
: The split function can be specified in 1 of 3 different methods:&lt;br /&gt;
:# subpkgname:&#039;&#039;&#039;splitfunc&#039;&#039;&#039;&lt;br /&gt;
:# $pkgname-&#039;&#039;&#039;splitfunc&#039;&#039;&#039;&lt;br /&gt;
:# &#039;&#039;&#039;splitfunc&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
: {{Note|Split function names &#039;&#039;&#039;cannot&#039;&#039;&#039; use hyphens; use the first method above if the subpackage name contains a hyphen (-) character, like this: &#039;&#039;subpkg-name:subpkg_name&#039;&#039;, where &amp;lt;code&amp;gt;subpkg-name&amp;lt;/code&amp;gt; is the name of the &#039;&#039;&#039;subpackage&#039;&#039;&#039; and &amp;lt;code&amp;gt;subpkg_name&amp;lt;/code&amp;gt; is the name of the &#039;&#039;&#039;subpackage&#039;s split function&#039;&#039;&#039;.}}&lt;br /&gt;
&lt;br /&gt;
: {{Tip|For more information, see the [[APKBUILD_examples:Subpackages|Subpackages example]].}}&lt;br /&gt;
&lt;br /&gt;
==== triggers ====&lt;br /&gt;
: Apk-tools can &amp;quot;monitor&amp;quot; directories and execute a trigger if any package installed/uninstalled any file in the monitored dir. The triggers are always execute after the apk action (install, uninstall, upgrade).&lt;br /&gt;
&lt;br /&gt;
: The triggers are specified in the format: &#039;&#039;scriptname&#039;&#039;=&#039;&#039;pathlist&#039;&#039; where &#039;&#039;scriptname&#039;&#039; is the (sub)package name + .trigger suffix and pathlist is : separated list of the dirs to monitor.&lt;br /&gt;
&lt;br /&gt;
: The &#039;&#039;&#039;triggers&#039;&#039;&#039; variable must include the triggers for subpackages too if they have any.&lt;br /&gt;
&lt;br /&gt;
: It is possible to use wildcards (*) in the dir list.&lt;br /&gt;
&lt;br /&gt;
==== url ====&lt;br /&gt;
: The homepage for the package.  This is to help users find upstream documentation and other information regarding the package.&lt;br /&gt;
&lt;br /&gt;
= Functions =&lt;br /&gt;
{{Note|All functions should consider the current working directory as undefined, and should therefore use the [[APKBUILD Reference#abuild-defined_variables|abuild-defined directory variables]] to their advantage.}}&lt;br /&gt;
&lt;br /&gt;
== abuild-defined functions ==&lt;br /&gt;
The following functions are provided by abuild and can be overridden:&lt;br /&gt;
&lt;br /&gt;
==== fetch() ====&lt;br /&gt;
: Downloads remote sources listed in &#039;&#039;source&#039;&#039; to &#039;&#039;SRCDEST&#039;&#039; (&#039;&#039;SRCDEST&#039;&#039; is configured in &#039;&#039;/etc/abuild.conf&#039;&#039;) and creates symlinks in &#039;&#039;$srcdir&#039;&#039;.&lt;br /&gt;
==== unpack() ====&lt;br /&gt;
: Unpacks .tgz, .tar.gz, .tar.bz2, .tar.lzma, .tar.xz, and .zip archives in &#039;&#039;$srcdir&#039;&#039; to &#039;&#039;$srcdir&#039;&#039;.&lt;br /&gt;
==== dev() ====&lt;br /&gt;
: Subpackage function for the &#039;&#039;&#039;$pkgname-dev&#039;&#039;&#039; package.  Without specifying a custom &#039;&#039;dev()&#039;&#039; function, abuild will call it&#039;s internal &#039;&#039;dev()&#039;&#039; function, which in turn calls &#039;&#039;default_dev()&#039;&#039;, which will move &#039;&#039;&amp;quot;$pkgdir&amp;quot;/usr/include&#039;&#039;, &#039;&#039;*.a&#039;&#039;, &#039;&#039;*.la&#039;&#039; and similar files to &#039;&#039;$subpkgdir&#039;&#039;.&lt;br /&gt;
==== doc() ====&lt;br /&gt;
: Subpackage function for the &#039;&#039;&#039;$pkgname-doc&#039;&#039;&#039; package.  Without specifying a custom &#039;&#039;doc()&#039;&#039; function, abuild will call it&#039;s internal &#039;&#039;doc()&#039;&#039; function, which in turn calls &#039;&#039;default_doc()&#039;&#039;, which will move &#039;&#039;&amp;quot;$pkgdir&amp;quot;/usr/share/doc&#039;&#039;, &#039;&#039;&amp;quot;$pkgdir&amp;quot;/usr/share/man&#039;&#039; and similar to &#039;&#039;$subpkgdir&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== User-defined functions ==&lt;br /&gt;
The following functions should be defined by the user: &lt;br /&gt;
&lt;br /&gt;
==== prepare() ====&lt;br /&gt;
: {{note|Please adjust old APKBUILDs, which still have a &#039;&#039;prepare()&#039;&#039; function that does the same as the &#039;&#039;default_prepare()&#039;&#039; when you edit them anyway.}}&lt;br /&gt;
: &#039;&#039;&#039;&#039;&#039;Optional&#039;&#039;.&#039;&#039;&#039;  Used for build preparation: patches, etc, should be applied here. When you don&#039;t specify a custom &#039;&#039;prepare()&#039;&#039;, the built-in &#039;&#039;default_prepare()&#039;&#039; from abuild will be used. It applies patches already (always prepare them in the &amp;lt;code&amp;gt;-p1&amp;lt;/code&amp;gt; format), so &#039;&#039;&#039;usually it makes sense to not create a custom &#039;&#039;prepare()&#039;&#039; function at all!&#039;&#039;&#039; If you do create one, call &#039;&#039;default_prepare()&#039;&#039; inside it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
prepare() {&lt;br /&gt;
    default_prepare&lt;br /&gt;
    # your custom code here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== build() ====&lt;br /&gt;
: &#039;&#039;&#039;Required.&#039;&#039;&#039;  This is the compilation stage.  This function will be called as the current user (unless the &#039;&#039;package()&#039;&#039; function is missing - for compatibility reasons).  If no compilation is needed, this function can contain a single line: &amp;lt;code&amp;gt;return 0&amp;lt;/code&amp;gt;&lt;br /&gt;
==== check() ====&lt;br /&gt;
: &#039;&#039;&#039;Recommended.&#039;&#039;&#039; This function is called right after the build stage.  It should check that the packaged thing is actually working, typically by running (integration) tests, if provided by upstream.  If there’s no (easy) way how to test the package, you can declare that it does not want to use &#039;&#039;check()&#039;&#039; by adding &amp;quot;!check&amp;quot; into the &#039;&#039;options&#039;&#039; variable (&amp;lt;code&amp;gt;options=&amp;quot;!check&amp;quot;&amp;lt;/code&amp;gt;).&lt;br /&gt;
==== package() ====&lt;br /&gt;
: &#039;&#039;&#039;Required.&#039;&#039;&#039;  This is the packaging stage.  Here, the built application and support files should be installed into &#039;&#039;&#039;$pkgdir&#039;&#039;&#039;.  If this is a metapackage, this function can contain a single line: &amp;lt;code&amp;gt;mkdir -p &amp;quot;$pkgdir&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Note|Building in fakeroot will reduce performance for parallel builds dramatically.  It is for this reason that we split the build and package process into two separate functions.}}&lt;br /&gt;
&lt;br /&gt;
= Examples =&lt;br /&gt;
The [[APKBUILD examples]] page will assist you in understanding how to create an APKBUILD.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Apkindex_format&amp;diff=14237</id>
		<title>Apkindex format</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Apkindex_format&amp;diff=14237"/>
		<updated>2017-12-23T03:52:44Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= The APKINDEX.tar.gz format =&lt;br /&gt;
From apk-tools-2.0_pre15 there was added support for package signing. The caused the index format to chage, as it needs to contain a signature for the repository. This document explains how the new index works and how it is created. This is intended to be a reference for abuild developers. Other developers should use the tools provided from abuild.&lt;br /&gt;
&lt;br /&gt;
See the [https://git.alpinelinux.org/cgit/abuild/tree/abuild.in#n1488 abuild source] and [https://git.alpinelinux.org/cgit/abuild/tree/abuild-sign.in#n18 abuild-sign] source for more details about how this indexes and signatures are constructed behind the scenes.&lt;br /&gt;
&lt;br /&gt;
= Creating APKINDEX.tar.gz =&lt;br /&gt;
The APKINDEX.tar.gz is created by concatenating 2 other tar.gz files, signature.tar.gz and APKINDEX.unsigned.tar.gz.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|cat signature.tar.gz APKINDEX.unsigned.tar.gz &amp;gt; APKINDEX.tar.gz}}&lt;br /&gt;
&lt;br /&gt;
== Creating signature.tar.gz Manually ==&lt;br /&gt;
First we create a signature file for APKINDEX.unsigned.tar.gz, using our [[Abuild_and_Helpers#abuild-keygen|private key]].&lt;br /&gt;
{{Cmd|openssl dgst -sha1 -sign &#039;&#039;privatekeyfile&#039;&#039; -out .SIGN.RSA.&#039;&#039;nameofpublickey&#039;&#039; APKINDEX.unsigned.tar.gz}}&lt;br /&gt;
&lt;br /&gt;
Then we put this in a tar file, without the &#039;&#039;end-of-tar&#039;&#039; record at the end of the file. This is because we will concatenate this tar archive with the index tar archive.&lt;br /&gt;
&lt;br /&gt;
 tar -c .SIGN.RSA.&#039;&#039;nameofpublickey&#039;&#039; | abuild-tar --cut | gzip -9 &amp;gt; signature.tar.gz&lt;br /&gt;
&lt;br /&gt;
The name of public key should be the email address of the developer.&lt;br /&gt;
&lt;br /&gt;
== Creating APKINDEX.unsigned.tar.gz ==&lt;br /&gt;
The APKINDEX.unsigned.tar.gz is an old 1.9 style index file in a tar archive. This is created with:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|apk index -o APKINDEX.unsigned.tar.gz *.apk}}&lt;br /&gt;
&lt;br /&gt;
== Signing APKINDEX.unsigned.tar.gz ==&lt;br /&gt;
Without a signature apk-tools will not trust the index file and will require the &amp;lt;tt&amp;gt;--allow-untrusted&amp;lt;/tt&amp;gt; flag for all operations involving the index. To sign an index requires a key, if you don&#039;t already have a key the easiest way to generate one is to use the &amp;lt;tt&amp;gt;abuild-keygen&amp;lt;/tt&amp;gt; command like so:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|apk add abuild&lt;br /&gt;
abuild-keygen -a -i}}&lt;br /&gt;
&lt;br /&gt;
It will prompt you for a filename to save the keypair. Enter file in which to save the key. The standard practice for naming the key is to use your email address or the email address of a maintainer&#039;s mailing list as a prefix for the filename of the keypair followed by an alphanumeric suffix, which is generated by the abuild-keygen tool.&lt;br /&gt;
&lt;br /&gt;
For this example, we will use &amp;lt;tt&amp;gt;alpine-devel@example.com-5629d7e6.rsa&amp;lt;/tt&amp;gt; which will create the &amp;lt;tt&amp;gt;alpine-devel@example.com-5629d7e6.rsa&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;alpine-devel@example.com-5629d7e6.rsa.pub&amp;lt;/tt&amp;gt; keypair and copy the public key to {{Path|/etc/apk/keys/}}. Make sure you keep a copy of your private key somewhere safe because you will need it if you add any packages to the repo in the future since you will need to re-sign the updated index.&lt;br /&gt;
&lt;br /&gt;
Finally, sign the index. Ensure that you provide the full path to the private key or &amp;lt;tt&amp;gt;abuild-sign&amp;lt;/tt&amp;gt; will not be able to find it.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|abuild-sign -k ~/alpine-devel@example.com-5629d7e6.rsa /repo/x86_64/APKINDEX.tar.gz}}&lt;br /&gt;
&lt;br /&gt;
For hosts to trust this index ensure that the public component of the key you generated exists in their {{Path|/etc/apk/keys}} directory.&lt;br /&gt;
&lt;br /&gt;
[[Category:Package Manager]] [[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Install_Alpine_on_Amazon_EC2&amp;diff=14201</id>
		<title>Install Alpine on Amazon EC2</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Install_Alpine_on_Amazon_EC2&amp;diff=14201"/>
		<updated>2017-12-10T05:44:35Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: /* Create an Apkovl File */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;EC2 instances are available in a variety of [https://aws.amazon.com/ec2/instance-types/ different sizes] with different specifications but all of them currently run on one of two types of virtualization technology: [https://en.wikipedia.org/wiki/Paravirtualization paravirtualization] (PV) or [https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine hardware virtual machine] (HVM).&lt;br /&gt;
&lt;br /&gt;
PV instances boot with a special boot loader called PV-GRUB, which starts the boot cycle and then chain loads the kernel specified in the menu.lst file on your image. Paravirtual guests can run on host hardware that does not have explicit support for virtualization, but they cannot take advantage of special hardware extensions such as enhanced networking or GPU processing.&lt;br /&gt;
&lt;br /&gt;
HVM instances are presented with a fully virtualized set of hardware and boot by executing the master boot record of the root block device of your image. This virtualization type provides the ability to run an operating system directly on top of a virtual machine without any modification, as if it were run on the bare-metal hardware. The Amazon EC2 host system emulates some or all of the underlying hardware that is presented to the guest. (from: [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/virtualization_types.html Linux AMI Virtualization Types]).&lt;br /&gt;
&lt;br /&gt;
Only older instance types support PV instances, all new instance types use an HVM hypervisor. For the purposes of setting up Alpine Linux on EC2 this mainly impacts the way the bootloader is configured.&lt;br /&gt;
&lt;br /&gt;
EC2 instances are created from templates called Amazon Machine Images (AMI). AMIs are built using existing running instances and then are turned into AMIs using a snapshot process. Note that an AMI is region specific so you must either follow this guide in each region you plan to deploy Alpine Linux instances or you must copy the AMI using either the console or the AWS command line client to each region you plan to use.&lt;br /&gt;
&lt;br /&gt;
All instance types are 64-bit. 32-bit images will not work.&lt;br /&gt;
&lt;br /&gt;
This guide will create the smallest possible (1GB) EBS-backed image which acts as a virtual USB stick that will boot and run Alpine Linux.  &lt;br /&gt;
= Initial Setup =&lt;br /&gt;
All AMI creation tasks follow the same set of setup steps which require a running Linux instance and an attached EBS volume. The Linux instance will only be used to setup the root filesystem for your Alpine Linux system so any distro works, Amazon Linux is the default so, where relevant, this guide will use that distro.&lt;br /&gt;
&lt;br /&gt;
# Create an EC2 instance, t2.micro running Amazon Linux should suffice&lt;br /&gt;
# Create a 1GB EBS volume and attach it to the instance as {{Path|/dev/sdf}} (this will appear on an HVM instance as {{Path|/dev/xvdf}})&lt;br /&gt;
# Format the disk as ext4, there is no need to partition the drive: {{Cmd|mkfs.ext4 /dev/xvdf}}&lt;br /&gt;
# Mount the drive to the host: {{Cmd|mkdir /mnt/target &amp;amp;&amp;amp; mount /dev/xvdf /mnt/target}}&lt;br /&gt;
# Fetch a copy of the latest virt release: {{Cmd|curl -o /tmp/alpine-release.iso http://dl-4.alpinelinux.org/alpine/v3.7/releases/x86_64/alpine-virt-3.7.0-x86_64.iso}}&lt;br /&gt;
# Mount the release iso: {{Cmd|mkdir /mnt/source &amp;amp;&amp;amp; mount -o loop /tmp/alpine-release.iso /mnt/source}}&lt;br /&gt;
# Copy the files to the target {{Cmd|cp -av /mnt/source/boot /mnt/target}}&lt;br /&gt;
&lt;br /&gt;
The sudo package is not included in the on-disk repository for the virt image which means that it will not be accessible for installation at system boot time; to enable this you will need a copy of the repository from the extended image. Download this image and copy the &amp;lt;tt&amp;gt;apks&amp;lt;/tt&amp;gt; folder to the target.&lt;br /&gt;
&lt;br /&gt;
# Fetch a copy of the latest virt release: {{Cmd|curl -o /tmp/alpine-extended-release.iso http://dl-4.alpinelinux.org/alpine/v3.7/releases/x86_64/alpine-extended-3.7.0-x86_64.iso}}&lt;br /&gt;
# Mount the release iso: {{Cmd|mkdir /mnt/source-extended &amp;amp;&amp;amp; mount -o loop /tmp/alpine-release-extended.iso /mnt/source-extended}}&lt;br /&gt;
# Copy the files to the target {{Cmd|cp -av /mnt/source-extended/apks /mnt/target}}&lt;br /&gt;
&lt;br /&gt;
Because the packages on Amazon Linux are a little older than the ones that ship with Alpine and because you will be creating an apkovl file for initial system configuration, you will either need an existing Alpine Linux system or a copy of the minirootfs image into which you can chroot. To setup a chroot:&lt;br /&gt;
&lt;br /&gt;
# Fetch a copy of the latest minirootfs release: {{Cmd|curl -o /tmp/alpine-minirootfs.tar.gz http://dl-4.alpinelinux.org/alpine/v3.7/releases/x86_64/alpine-minirootfs-3.7.0-x86_64.tar.gz}}&lt;br /&gt;
# Unpack the root fs: {{Cmd|mkdir /tmp/alpine-chroot &amp;amp;&amp;amp; tar -C /tmp/alpine-chroot -xvf /tmp/alpine-minirootfs.tar.gz}}&lt;br /&gt;
# Copy the system resolv.conf into the chroot so you will have internet access: {{Cmd|cp /etc/resolv.conf /tmp/alpine-chroot/etc}}&lt;br /&gt;
&lt;br /&gt;
= Create an Apkovl File =&lt;br /&gt;
The top level of the EBS volume will be scanned during boot for files named &amp;lt;tt&amp;gt;*.apkovl.tar.gz&amp;lt;/tt&amp;gt; and the first one that is found will be unpacked and overlayed onto the file system. The goal of this archive is to configure the system so that you will be able to login after the system boots. At a minimum this means:&lt;br /&gt;
&lt;br /&gt;
* Configure networking to use dhcp and start when the system boots&lt;br /&gt;
* Install an SSH daemon&lt;br /&gt;
* Configure a user with your SSH keys&lt;br /&gt;
* Enable sudo so that you can gain root access&lt;br /&gt;
&lt;br /&gt;
Setup the chroot and chroot into it, then add any desired packages. The &amp;lt;tt&amp;gt;busybox-initscripts&amp;lt;/tt&amp;gt; package provides the required files for udhcpc which will allow DHCP to be enabled. The &amp;lt;tt&amp;gt;syslinux&amp;lt;/tt&amp;gt; package is required to install the boot-loader but is not required on the final system.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /tmp/alpine-chroot/mnt/target&lt;br /&gt;
mount -o bind /mnt/target /tmp/alpine-chroot/mnt/target&lt;br /&gt;
mount -t proc none /tmp/alpine-chroot/proc&lt;br /&gt;
mount -t devtmpfs none /tmp/alpine-chroot/dev&lt;br /&gt;
mount -t sysfs none /tmp/alpine-chroot/sys&lt;br /&gt;
&lt;br /&gt;
chroot /tmp/alpine-chroot sh&lt;br /&gt;
&lt;br /&gt;
apk update&lt;br /&gt;
apk add alpine-conf sudo openssh busybox-initscripts syslinux&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Alpine init system will start up the core required services if the file {{Path|/etc/.default_boot_services}} exists, so create that.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
touch etc/.default_boot_services&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Setup networking:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cat &amp;gt; /etc/network/interfaces &amp;lt;&amp;lt;EOF&lt;br /&gt;
auto lo&lt;br /&gt;
iface lo inet loopback&lt;br /&gt;
&lt;br /&gt;
auto eth0&lt;br /&gt;
iface eth0 inet dhcp&lt;br /&gt;
EOF&lt;br /&gt;
&lt;br /&gt;
ln -s /etc/init.d/networking /etc/runlevels/default/&lt;br /&gt;
ln -s /etc/init.d/sshd /etc/runlevels/default/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add a user, set an SSH key, and ensure that this user can sudo:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adduser -D -s /bin/sh alpine&lt;br /&gt;
addgroup alpine wheel&lt;br /&gt;
&lt;br /&gt;
mkdir /home/alpine/.ssh&lt;br /&gt;
chmod 700 /home/alpine/.ssh&lt;br /&gt;
cat &amp;gt; /home/alpine/.ssh/authorized_keys &amp;lt;&amp;lt;EOF&lt;br /&gt;
... your ssh public key(s) ...&lt;br /&gt;
EOF&lt;br /&gt;
chmod 600 /home/alpine/.ssh/authorized_keys&lt;br /&gt;
&lt;br /&gt;
sed -i &#039;/%wheel/s/^# //&#039; /etc/sudoers&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Exclude backup files and any files that are going to exist in the unpacked image. Then create an apkovl bundle.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
lbu exclude \&lt;br /&gt;
    etc/group- etc/passwd- etc/shadow- \&lt;br /&gt;
    etc/apk/keys etc/apk/arch etc/apk/repositories \&lt;br /&gt;
    etc/os-release \&lt;br /&gt;
    etc/issue \&lt;br /&gt;
    etc/alpine-release&lt;br /&gt;
lbu include /home/alpine/.ssh&lt;br /&gt;
lbu package amazon.apkovl.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything you expect to be in the apovl file is there and if not you can [[Manually_editing_a_existing_apkovl|modify the apkovl]].&lt;br /&gt;
&lt;br /&gt;
Finally, copy the apkovl to {{Path|/mnt/target}}.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cp amazon.apkovl.tar.gz /mnt/target&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= EBS Backed HVM AMI =&lt;br /&gt;
For HVM instances you will need to install a boot-loader. Any bootloader should do the trick but this guide will use syslinux because it&#039;s fast and small and you don&#039;t have to support any odd hardware or system layout.&lt;br /&gt;
&lt;br /&gt;
First you will need to ensure that the ext4 driver is loaded and may as well shorten the timeout to speed instance boot time.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|sed -i \&lt;br /&gt;
    -e &#039;/usb-storage/s//usb-storage,ext4/&#039; \&lt;br /&gt;
    -e &#039;/^TIMEOUT/s/20/2/&#039; \&lt;br /&gt;
    /mnt/target/boot/syslinux/syslinux.cfg}}&lt;br /&gt;
&lt;br /&gt;
Finally, install the bootloader: {{Cmd|extlinux -i /mnt/target/boot}}&lt;br /&gt;
&lt;br /&gt;
= EBS Backed PV AMI =&lt;br /&gt;
For PV AMIs PV-GRUB will attempt to read {{Path|/boot/grub/menu.lst}} to load the kernel. First create a {{Path|/boot/grub/grub.conf}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir -p /mnt/target/boot/grub&lt;br /&gt;
&lt;br /&gt;
cat &amp;gt; target/boot/grub/grub.conf &amp;lt;&amp;lt;EOF &lt;br /&gt;
default=0&lt;br /&gt;
timeout=2&lt;br /&gt;
hiddenmenu&lt;br /&gt;
&lt;br /&gt;
title Alpine Linux&lt;br /&gt;
root (hd0)&lt;br /&gt;
kernel /boot/vmlinuz-virthardened alpine_dev=xvda1:ext4 modules=loop,squashfs,sd-mod,ext4 console=hvc0 pax_nouderef BOOT_IMAGE=/boot/vmlinuz-virthardened&lt;br /&gt;
initrd /boot/initramfs-virthardened&lt;br /&gt;
EOF&lt;br /&gt;
&lt;br /&gt;
ln -s /mnt/target/boot/grub/grub.conf  /mnt/target/boot/grub/menu.lst&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Create the AMI =&lt;br /&gt;
The following will need to be done in the AWS console.&lt;br /&gt;
&lt;br /&gt;
# Detach the new volume (make note of the volume ID)&lt;br /&gt;
# Launch a new instance, use the defaults; you are going to cannibalize it in a moment&lt;br /&gt;
# Once the instance starts, stop but do not terminate it&lt;br /&gt;
# Under EBS, detach the existing volume, and attach the Alpine Linux volume as {{Path|/dev/xvda}} (for HVM) or {{Path|/dev/sda1}} (for PV)&lt;br /&gt;
# Restart the instance&lt;br /&gt;
# Log in and make sure it works&lt;br /&gt;
# Do any final cleanups necessary. Only make changes appropriate for an AMI, you are going to snapshot this instance and use it as the base for the AMI.&lt;br /&gt;
# Stop but do not terminate the instance&lt;br /&gt;
# Right click the stopped instance and choose &#039;Create Image (EBS AMI)&#039;&lt;br /&gt;
# Once the AMI creation finishes you can cleanup the instances and EBS volumes used&lt;br /&gt;
&lt;br /&gt;
[[Category:Virtualization]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Install_Alpine_on_Amazon_EC2&amp;diff=14200</id>
		<title>Install Alpine on Amazon EC2</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Install_Alpine_on_Amazon_EC2&amp;diff=14200"/>
		<updated>2017-12-10T05:30:35Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;EC2 instances are available in a variety of [https://aws.amazon.com/ec2/instance-types/ different sizes] with different specifications but all of them currently run on one of two types of virtualization technology: [https://en.wikipedia.org/wiki/Paravirtualization paravirtualization] (PV) or [https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine hardware virtual machine] (HVM).&lt;br /&gt;
&lt;br /&gt;
PV instances boot with a special boot loader called PV-GRUB, which starts the boot cycle and then chain loads the kernel specified in the menu.lst file on your image. Paravirtual guests can run on host hardware that does not have explicit support for virtualization, but they cannot take advantage of special hardware extensions such as enhanced networking or GPU processing.&lt;br /&gt;
&lt;br /&gt;
HVM instances are presented with a fully virtualized set of hardware and boot by executing the master boot record of the root block device of your image. This virtualization type provides the ability to run an operating system directly on top of a virtual machine without any modification, as if it were run on the bare-metal hardware. The Amazon EC2 host system emulates some or all of the underlying hardware that is presented to the guest. (from: [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/virtualization_types.html Linux AMI Virtualization Types]).&lt;br /&gt;
&lt;br /&gt;
Only older instance types support PV instances, all new instance types use an HVM hypervisor. For the purposes of setting up Alpine Linux on EC2 this mainly impacts the way the bootloader is configured.&lt;br /&gt;
&lt;br /&gt;
EC2 instances are created from templates called Amazon Machine Images (AMI). AMIs are built using existing running instances and then are turned into AMIs using a snapshot process. Note that an AMI is region specific so you must either follow this guide in each region you plan to deploy Alpine Linux instances or you must copy the AMI using either the console or the AWS command line client to each region you plan to use.&lt;br /&gt;
&lt;br /&gt;
All instance types are 64-bit. 32-bit images will not work.&lt;br /&gt;
&lt;br /&gt;
This guide will create the smallest possible (1GB) EBS-backed image which acts as a virtual USB stick that will boot and run Alpine Linux.  &lt;br /&gt;
= Initial Setup =&lt;br /&gt;
All AMI creation tasks follow the same set of setup steps which require a running Linux instance and an attached EBS volume. The Linux instance will only be used to setup the root filesystem for your Alpine Linux system so any distro works, Amazon Linux is the default so, where relevant, this guide will use that distro.&lt;br /&gt;
&lt;br /&gt;
# Create an EC2 instance, t2.micro running Amazon Linux should suffice&lt;br /&gt;
# Create a 1GB EBS volume and attach it to the instance as {{Path|/dev/sdf}} (this will appear on an HVM instance as {{Path|/dev/xvdf}})&lt;br /&gt;
# Format the disk as ext4, there is no need to partition the drive: {{Cmd|mkfs.ext4 /dev/xvdf}}&lt;br /&gt;
# Mount the drive to the host: {{Cmd|mkdir /mnt/target &amp;amp;&amp;amp; mount /dev/xvdf /mnt/target}}&lt;br /&gt;
# Fetch a copy of the latest virt release: {{Cmd|curl -o /tmp/alpine-release.iso http://dl-4.alpinelinux.org/alpine/v3.7/releases/x86_64/alpine-virt-3.7.0-x86_64.iso}}&lt;br /&gt;
# Mount the release iso: {{Cmd|mkdir /mnt/source &amp;amp;&amp;amp; mount -o loop /tmp/alpine-release.iso /mnt/source}}&lt;br /&gt;
# Copy the files to the target {{Cmd|cp -av /mnt/source/boot /mnt/target}}&lt;br /&gt;
&lt;br /&gt;
The sudo package is not included in the on-disk repository for the virt image which means that it will not be accessible for installation at system boot time; to enable this you will need a copy of the repository from the extended image. Download this image and copy the &amp;lt;tt&amp;gt;apks&amp;lt;/tt&amp;gt; folder to the target.&lt;br /&gt;
&lt;br /&gt;
# Fetch a copy of the latest virt release: {{Cmd|curl -o /tmp/alpine-extended-release.iso http://dl-4.alpinelinux.org/alpine/v3.7/releases/x86_64/alpine-extended-3.7.0-x86_64.iso}}&lt;br /&gt;
# Mount the release iso: {{Cmd|mkdir /mnt/source-extended &amp;amp;&amp;amp; mount -o loop /tmp/alpine-release-extended.iso /mnt/source-extended}}&lt;br /&gt;
# Copy the files to the target {{Cmd|cp -av /mnt/source-extended/apks /mnt/target}}&lt;br /&gt;
&lt;br /&gt;
Because the packages on Amazon Linux are a little older than the ones that ship with Alpine and because you will be creating an apkovl file for initial system configuration, you will either need an existing Alpine Linux system or a copy of the minirootfs image into which you can chroot. To setup a chroot:&lt;br /&gt;
&lt;br /&gt;
# Fetch a copy of the latest minirootfs release: {{Cmd|curl -o /tmp/alpine-minirootfs.tar.gz http://dl-4.alpinelinux.org/alpine/v3.7/releases/x86_64/alpine-minirootfs-3.7.0-x86_64.tar.gz}}&lt;br /&gt;
# Unpack the root fs: {{Cmd|mkdir /tmp/alpine-chroot &amp;amp;&amp;amp; tar -C /tmp/alpine-chroot -xvf /tmp/alpine-minirootfs.tar.gz}}&lt;br /&gt;
# Copy the system resolv.conf into the chroot so you will have internet access: {{Cmd|cp /etc/resolv.conf /tmp/alpine-chroot/etc}}&lt;br /&gt;
&lt;br /&gt;
= Create an Apkovl File =&lt;br /&gt;
The top level of the EBS volume will be scanned during boot for files named &amp;lt;tt&amp;gt;*.apkovl.tar.gz&amp;lt;/tt&amp;gt; and the first one that is found will be unpacked and overlayed onto the file system. The goal of this archive is to configure the system so that you will be able to login after the system boots. At a minimum this means:&lt;br /&gt;
&lt;br /&gt;
* Configure networking to use dhcp and start when the system boots&lt;br /&gt;
* Install an SSH daemon&lt;br /&gt;
* Configure a user with your SSH keys&lt;br /&gt;
* Enable sudo so that you can gain root access&lt;br /&gt;
&lt;br /&gt;
Setup the chroot and chroot into it, then add any desired packages. The &amp;lt;tt&amp;gt;busybox-initscripts&amp;lt;/tt&amp;gt; package provides the required files for udhcpc which will allow DHCP to be enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /tmp/alpine-chroot/mnt/target&lt;br /&gt;
mount -o bind /mnt/target /tmp/alpine-chroot/mnt/target&lt;br /&gt;
mount -t proc none /tmp/alpine-chroot/proc&lt;br /&gt;
mount -t devtmpfs none /tmp/alpine-chroot/dev&lt;br /&gt;
mount -t sysfs none /tmp/alpine-chroot/sys&lt;br /&gt;
&lt;br /&gt;
chroot /tmp/alpine-chroot sh&lt;br /&gt;
&lt;br /&gt;
apk update&lt;br /&gt;
apk add alpine-conf sudo openssh busybox-initscripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Alpine init system will start up the core required services if the file {{Path|/etc/.default_boot_services}} exists, so create that.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
touch etc/.default_boot_services&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Setup networking:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cat &amp;gt; /etc/network/interfaces &amp;lt;&amp;lt;EOF&lt;br /&gt;
auto lo&lt;br /&gt;
iface lo inet loopback&lt;br /&gt;
&lt;br /&gt;
auto eth0&lt;br /&gt;
iface eth0 inet dhcp&lt;br /&gt;
EOF&lt;br /&gt;
&lt;br /&gt;
ln -s /etc/init.d/networking /etc/runlevels/default/&lt;br /&gt;
ln -s /etc/init.d/sshd /etc/runlevels/default/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add a user, set an SSH key, and ensure that this user can sudo:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adduser -D -s /bin/sh alpine&lt;br /&gt;
addgroup alpine wheel&lt;br /&gt;
&lt;br /&gt;
mkdir /home/alpine/.ssh&lt;br /&gt;
chmod 700 /home/alpine/.ssh&lt;br /&gt;
cat &amp;gt; /home/alpine/.ssh/authorized_keys &amp;lt;&amp;lt;EOF&lt;br /&gt;
... your ssh public key(s) ...&lt;br /&gt;
EOF&lt;br /&gt;
chmod 600 /home/alpine/.ssh/authorized_keys&lt;br /&gt;
&lt;br /&gt;
sed -i &#039;/%wheel/s/^# //&#039; /etc/sudoers&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Exclude backup files and any files that are going to exist in the unpacked image. Then create an apkovl bundle.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
lbu exclude \&lt;br /&gt;
    etc/group- etc/passwd- etc/shadow- \&lt;br /&gt;
    etc/apk/keys etc/apk/arch etc/apk/repositories \&lt;br /&gt;
    etc/os-release \&lt;br /&gt;
    etc/issue \&lt;br /&gt;
    etc/alpine-release&lt;br /&gt;
lbu include /home/alpine/.ssh&lt;br /&gt;
lbu package amazon.apkovl.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything you expect to be in the apovl file is there and if not you can [[Manually_editing_a_existing_apkovl|modify the apkovl]].&lt;br /&gt;
&lt;br /&gt;
Finally, copy the apkovl to {{Path|/mnt/target}}.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cp amazon.apkovl.tar.gz /mnt/target&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= EBS Backed HVM AMI =&lt;br /&gt;
For HVM instances you will need to install a boot-loader. Any bootloader should do the trick but this guide will use syslinux because it&#039;s fast and small and you don&#039;t have to support any odd hardware or system layout.&lt;br /&gt;
&lt;br /&gt;
First you will need to ensure that the ext4 driver is loaded and may as well shorten the timeout to speed instance boot time.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|sed -i \&lt;br /&gt;
    -e &#039;/usb-storage/s//usb-storage,ext4/&#039; \&lt;br /&gt;
    -e &#039;/^TIMEOUT/s/20/2/&#039; \&lt;br /&gt;
    /mnt/target/boot/syslinux/syslinux.cfg}}&lt;br /&gt;
&lt;br /&gt;
Finally, install the bootloader: {{Cmd|extlinux -i /mnt/target/boot}}&lt;br /&gt;
&lt;br /&gt;
= EBS Backed PV AMI =&lt;br /&gt;
For PV AMIs PV-GRUB will attempt to read {{Path|/boot/grub/menu.lst}} to load the kernel. First create a {{Path|/boot/grub/grub.conf}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir -p /mnt/target/boot/grub&lt;br /&gt;
&lt;br /&gt;
cat &amp;gt; target/boot/grub/grub.conf &amp;lt;&amp;lt;EOF &lt;br /&gt;
default=0&lt;br /&gt;
timeout=2&lt;br /&gt;
hiddenmenu&lt;br /&gt;
&lt;br /&gt;
title Alpine Linux&lt;br /&gt;
root (hd0)&lt;br /&gt;
kernel /boot/vmlinuz-virthardened alpine_dev=xvda1:ext4 modules=loop,squashfs,sd-mod,ext4 console=hvc0 pax_nouderef BOOT_IMAGE=/boot/vmlinuz-virthardened&lt;br /&gt;
initrd /boot/initramfs-virthardened&lt;br /&gt;
EOF&lt;br /&gt;
&lt;br /&gt;
ln -s /mnt/target/boot/grub/grub.conf  /mnt/target/boot/grub/menu.lst&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Create the AMI =&lt;br /&gt;
The following will need to be done in the AWS console.&lt;br /&gt;
&lt;br /&gt;
# Detach the new volume (make note of the volume ID)&lt;br /&gt;
# Launch a new instance, use the defaults; you are going to cannibalize it in a moment&lt;br /&gt;
# Once the instance starts, stop but do not terminate it&lt;br /&gt;
# Under EBS, detach the existing volume, and attach the Alpine Linux volume as {{Path|/dev/xvda}} (for HVM) or {{Path|/dev/sda1}} (for PV)&lt;br /&gt;
# Restart the instance&lt;br /&gt;
# Log in and make sure it works&lt;br /&gt;
# Do any final cleanups necessary. Only make changes appropriate for an AMI, you are going to snapshot this instance and use it as the base for the AMI.&lt;br /&gt;
# Stop but do not terminate the instance&lt;br /&gt;
# Right click the stopped instance and choose &#039;Create Image (EBS AMI)&#039;&lt;br /&gt;
# Once the AMI creation finishes you can cleanup the instances and EBS volumes used&lt;br /&gt;
&lt;br /&gt;
[[Category:Virtualization]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=User:Mcrute&amp;diff=14199</id>
		<title>User:Mcrute</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=User:Mcrute&amp;diff=14199"/>
		<updated>2017-12-10T05:25:26Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Mike Crute =&lt;br /&gt;
Software engineer by day, tinkerer by night. I like to document things. Feel free to email me, my email address is my first name at my last name dot us.&lt;br /&gt;
&lt;br /&gt;
My words and opinions are my own and do not reflect the values or opinions of my employers past, present, or future.&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=User:Mcrute&amp;diff=14198</id>
		<title>User:Mcrute</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=User:Mcrute&amp;diff=14198"/>
		<updated>2017-12-10T05:24:50Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Mike Crute =&lt;br /&gt;
Software engineer by day, tinkerer by night. I like to document things. Feel free to email me, my email address is my first name at my last name dot us.&lt;br /&gt;
&lt;br /&gt;
My words and opinions are my own and do not reflect the values or opinions of my employers past or present.&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=User:Mcrute&amp;diff=14197</id>
		<title>User:Mcrute</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=User:Mcrute&amp;diff=14197"/>
		<updated>2017-12-10T05:24:40Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Mike Crute =&lt;br /&gt;
Software engineer by day, tinkerer by night. I like to document things. Feel free to email me, my email address is my first name at my last name dot me.&lt;br /&gt;
&lt;br /&gt;
My words and opinions are my own and do not reflect the values or opinions of my employers past or present.&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=User:Mcrute&amp;diff=14196</id>
		<title>User:Mcrute</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=User:Mcrute&amp;diff=14196"/>
		<updated>2017-12-10T05:24:03Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: Created page with &amp;quot;= Mike Crute = Software engineer by day, tinkerer by night. I like to document things.  My words and opinions are my own and do not reflect the values or opinions of my employ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Mike Crute =&lt;br /&gt;
Software engineer by day, tinkerer by night. I like to document things.&lt;br /&gt;
&lt;br /&gt;
My words and opinions are my own and do not reflect the values or opinions of my employers past or present.&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Install_Alpine_on_Amazon_EC2&amp;diff=14195</id>
		<title>Install Alpine on Amazon EC2</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Install_Alpine_on_Amazon_EC2&amp;diff=14195"/>
		<updated>2017-12-10T05:16:44Z</updated>

		<summary type="html">&lt;p&gt;Mcrute: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;EC2 instances are available in a variety of [https://aws.amazon.com/ec2/instance-types/ different sizes] with different specifications but all of them currently run on one of two types of virtualization technology: [https://en.wikipedia.org/wiki/Paravirtualization paravirtualization] (PV) or [https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine hardware virtual machine] (HVM).&lt;br /&gt;
&lt;br /&gt;
PV instances boot with a special boot loader called PV-GRUB, which starts the boot cycle and then chain loads the kernel specified in the menu.lst file on your image. Paravirtual guests can run on host hardware that does not have explicit support for virtualization, but they cannot take advantage of special hardware extensions such as enhanced networking or GPU processing.&lt;br /&gt;
&lt;br /&gt;
HVM instances are presented with a fully virtualized set of hardware and boot by executing the master boot record of the root block device of your image. This virtualization type provides the ability to run an operating system directly on top of a virtual machine without any modification, as if it were run on the bare-metal hardware. The Amazon EC2 host system emulates some or all of the underlying hardware that is presented to the guest. (from: [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/virtualization_types.html Linux AMI Virtualization Types]).&lt;br /&gt;
&lt;br /&gt;
Only older instance types support PV instances, all new instance types use an HVM hypervisor. For the purposes of setting up Alpine Linux on EC2 this mainly impacts the way the bootloader is configured.&lt;br /&gt;
&lt;br /&gt;
EC2 instances are created from templates called Amazon Machine Images (AMI). AMIs are built using existing running instances and then are turned into AMIs using a snapshot process. Note that an AMI is region specific so you must either follow this guide in each region you plan to deploy Alpine Linux instances or you must copy the AMI using either the console or the AWS command line client to each region you plan to use.&lt;br /&gt;
&lt;br /&gt;
All instance types are 64-bit. 32-bit images will not work.&lt;br /&gt;
&lt;br /&gt;
This guide will create the smallest possible (1GB) EBS-backed image which acts as a virtual USB stick that will boot and run Alpine Linux.  &lt;br /&gt;
= Initial Setup =&lt;br /&gt;
All AMI creation tasks follow the same set of setup steps which require a running Linux instance and an attached EBS volume. The Linux instance will only be used to setup the root filesystem for your Alpine Linux system so any distro works, Amazon Linux is the default so, where relevant, this guide will use that distro.&lt;br /&gt;
&lt;br /&gt;
# Create an EC2 instance, t2.micro running Amazon Linux should suffice&lt;br /&gt;
# Create a 1GB EBS volume and attach it to the instance as &amp;lt;tt&amp;gt;/dev/sdf&amp;lt;/tt&amp;gt; (this will appear on an HVM instance as &amp;lt;tt&amp;gt;/dev/xvdf&amp;lt;/tt&amp;gt;)&lt;br /&gt;
# Format the disk as ext4, there is no need to partition the drive: {{Cmd|mkfs.ext4 /dev/xvdf}}&lt;br /&gt;
# Mount the drive to the host: {{Cmd|mkdir /mnt/target &amp;amp;&amp;amp; mount /dev/xvdf /mnt/target}}&lt;br /&gt;
# Fetch a copy of the latest virt release: {{Cmd|curl -o /tmp/alpine-release.iso http://dl-4.alpinelinux.org/alpine/v3.7/releases/x86_64/alpine-virt-3.7.0-x86_64.iso}}&lt;br /&gt;
# Mount the release iso: {{Cmd|mkdir /mnt/source &amp;amp;&amp;amp; mount -o loop /tmp/alpine-release.iso /mnt/source}}&lt;br /&gt;
# Copy the files to the target {{Cmd|cp -av /mnt/source/boot /mnt/target}}&lt;br /&gt;
&lt;br /&gt;
The sudo package is not included in the on-disk repository for the virt image which means that it will not be accessible for installation at system boot time; to enable this you will need a copy of the repository from the extended image. Download this image and copy the &amp;lt;tt&amp;gt;apks&amp;lt;/tt&amp;gt; folder to the target.&lt;br /&gt;
&lt;br /&gt;
# Fetch a copy of the latest virt release: {{Cmd|curl -o /tmp/alpine-extended-release.iso http://dl-4.alpinelinux.org/alpine/v3.7/releases/x86_64/alpine-extended-3.7.0-x86_64.iso}}&lt;br /&gt;
# Mount the release iso: {{Cmd|mkdir /mnt/source-extended &amp;amp;&amp;amp; mount -o loop /tmp/alpine-release-extended.iso /mnt/source-extended}}&lt;br /&gt;
# Copy the files to the target {{Cmd|cp -av /mnt/source-extended/apks /mnt/target}}&lt;br /&gt;
&lt;br /&gt;
Because the packages on Amazon Linux are a little older than the ones that ship with Alpine and because you will be creating an apkovl file for initial system configuration, you will either need an existing Alpine Linux system or a copy of the minirootfs image into which you can chroot. To setup a chroot:&lt;br /&gt;
&lt;br /&gt;
# Fetch a copy of the latest minirootfs release: {{Cmd|curl -o /tmp/alpine-minirootfs.tar.gz http://dl-4.alpinelinux.org/alpine/v3.7/releases/x86_64/alpine-minirootfs-3.7.0-x86_64.tar.gz}}&lt;br /&gt;
# Unpack the root fs: {{Cmd|mkdir /tmp/alpine-chroot &amp;amp;&amp;amp; tar -C /tmp/alpine-chroot -xvf /tmp/alpine-minirootfs.tar.gz}}&lt;br /&gt;
# Copy the system resolv.conf into the chroot so you will have internet access: {{Cmd|cp /etc/resolv.conf /tmp/alpine-chroot/etc}}&lt;br /&gt;
&lt;br /&gt;
= Create an Apkovl File =&lt;br /&gt;
The top level of the EBS volume will be scanned during boot for files named &amp;lt;tt&amp;gt;*.apkovl.tar.gz&amp;lt;/tt&amp;gt; and the first one that is found will be unpacked and overlayed onto the file system. The goal of this archive is to configure the system so that you will be able to login after the system boots. At a minimum this means:&lt;br /&gt;
&lt;br /&gt;
* Configure networking to use dhcp and start when the system boots&lt;br /&gt;
* Install an SSH daemon&lt;br /&gt;
* Configure a user with your SSH keys&lt;br /&gt;
* Enable sudo so that you can gain root access&lt;br /&gt;
&lt;br /&gt;
Setup the chroot and chroot into it, then add any desired packages. The &amp;lt;tt&amp;gt;busybox-initscripts&amp;lt;/tt&amp;gt; package provides the required files for udhcpc which will allow DHCP to be enabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir /tmp/alpine-chroot/mnt/target&lt;br /&gt;
mount -o bind /mnt/target /tmp/alpine-chroot/mnt/target&lt;br /&gt;
mount -t proc none /tmp/alpine-chroot/proc&lt;br /&gt;
mount -t devtmpfs none /tmp/alpine-chroot/dev&lt;br /&gt;
mount -t sysfs none /tmp/alpine-chroot/sys&lt;br /&gt;
&lt;br /&gt;
chroot /tmp/alpine-chroot sh&lt;br /&gt;
&lt;br /&gt;
apk update&lt;br /&gt;
apk add alpine-conf sudo openssh busybox-initscripts&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Alpine init system will start up the core required services if the file &amp;lt;tt&amp;gt;/etc/.default_boot_services&amp;lt;/tt&amp;gt; exists, so create that.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
touch etc/.default_boot_services&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Setup networking:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cat &amp;gt; /etc/network/interfaces &amp;lt;&amp;lt;EOF&lt;br /&gt;
auto lo&lt;br /&gt;
iface lo inet loopback&lt;br /&gt;
&lt;br /&gt;
auto eth0&lt;br /&gt;
iface eth0 inet dhcp&lt;br /&gt;
EOF&lt;br /&gt;
&lt;br /&gt;
ln -s /etc/init.d/networking /etc/runlevels/default/&lt;br /&gt;
ln -s /etc/init.d/sshd /etc/runlevels/default/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add a user, set an SSH key, and ensure that this user can sudo:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
adduser -D -s /bin/sh alpine&lt;br /&gt;
addgroup alpine wheel&lt;br /&gt;
&lt;br /&gt;
mkdir /home/alpine/.ssh&lt;br /&gt;
chmod 700 /home/alpine/.ssh&lt;br /&gt;
cat &amp;gt; /home/alpine/.ssh/authorized_keys &amp;lt;&amp;lt;EOF&lt;br /&gt;
... your ssh public key(s) ...&lt;br /&gt;
EOF&lt;br /&gt;
chmod 600 /home/alpine/.ssh/authorized_keys&lt;br /&gt;
&lt;br /&gt;
sed -i &#039;/%wheel/s/^# //&#039; /etc/sudoers&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Exclude backup files and any files that are going to exist in the unpacked image. Then create an apkovl bundle.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
lbu exclude \&lt;br /&gt;
    etc/group- etc/passwd- etc/shadow- \&lt;br /&gt;
    etc/apk/keys etc/apk/arch etc/apk/repositories \&lt;br /&gt;
    etc/os-release \&lt;br /&gt;
    etc/issue \&lt;br /&gt;
    etc/alpine-release&lt;br /&gt;
lbu include /home/alpine/.ssh&lt;br /&gt;
lbu package amazon.apkovl.tar.gz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verify that everything you expect to be in the apovl file is there and if not you can [[Manually_editing_a_existing_apkovl|modify the apkovl]].&lt;br /&gt;
&lt;br /&gt;
Finally, copy the apkovl to &amp;lt;tt&amp;gt;/mnt/target&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cp amazon.apkovl.tar.gz /mnt/target&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= EBS Backed HVM AMI =&lt;br /&gt;
For HVM instances you will need to install a boot-loader. Any bootloader should do the trick but this guide will use syslinux because it&#039;s fast and small and you don&#039;t have to support any odd hardware or system layout.&lt;br /&gt;
&lt;br /&gt;
First you will need to ensure that the ext4 driver is loaded and may as well shorten the timeout to speed instance boot time.&lt;br /&gt;
&lt;br /&gt;
{{Cmd|sed -i \&lt;br /&gt;
    -e &#039;/usb-storage/s//usb-storage,ext4/&#039; \&lt;br /&gt;
    -e &#039;/^TIMEOUT/s/20/2/&#039; \&lt;br /&gt;
    /mnt/target/boot/syslinux/syslinux.cfg}}&lt;br /&gt;
&lt;br /&gt;
Finally, install the bootloader: {{Cmd|extlinux -i /mnt/target/boot}}&lt;br /&gt;
&lt;br /&gt;
= EBS Backed PV AMI =&lt;br /&gt;
For PV AMIs PV-GRUB will attempt to read &amp;lt;tt&amp;gt;/boot/grub/menu.lst&amp;lt;/tt&amp;gt; to load the kernel. First create a &amp;lt;tt&amp;gt;/boot/grub/grub.conf&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mkdir -p /mnt/target/boot/grub&lt;br /&gt;
&lt;br /&gt;
cat &amp;gt; target/boot/grub/grub.conf &amp;lt;&amp;lt;EOF &lt;br /&gt;
default=0&lt;br /&gt;
timeout=2&lt;br /&gt;
hiddenmenu&lt;br /&gt;
&lt;br /&gt;
title Alpine Linux&lt;br /&gt;
root (hd0)&lt;br /&gt;
kernel /boot/vmlinuz-virthardened alpine_dev=xvda1:ext4 modules=loop,squashfs,sd-mod,ext4 console=hvc0 pax_nouderef BOOT_IMAGE=/boot/vmlinuz-virthardened&lt;br /&gt;
initrd /boot/initramfs-virthardened&lt;br /&gt;
EOF&lt;br /&gt;
&lt;br /&gt;
ln -s /mnt/target/boot/grub/grub.conf  /mnt/target/boot/grub/menu.lst&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Create the AMI =&lt;br /&gt;
The following will need to be done in the AWS console.&lt;br /&gt;
&lt;br /&gt;
# Detach the new volume (make note of the volume ID)&lt;br /&gt;
# Launch a new instance, use the defaults; you are going to cannibalize it in a moment&lt;br /&gt;
# Once the instance starts, stop but do not terminate it&lt;br /&gt;
# Under EBS, detach the existing volume, and attach the Alpine Linux volume as &amp;lt;tt&amp;gt;/dev/xvda&amp;lt;/tt&amp;gt; (for HVM) or &amp;lt;tt&amp;gt;/dev/sda1&amp;lt;/tt&amp;gt; (for PV)&lt;br /&gt;
# Restart the instance&lt;br /&gt;
# Log in and make sure it works&lt;br /&gt;
# Do any final cleanups necessary. Only make changes appropriate for an AMI, you are going to snapshot this instance and use it as the base for the AMI.&lt;br /&gt;
# Stop but do not terminate the instance&lt;br /&gt;
# Right click the stopped instance and choose &#039;Create Image (EBS AMI)&#039;&lt;br /&gt;
# Once the AMI creation finishes you can cleanup the instances and EBS volumes used&lt;br /&gt;
&lt;br /&gt;
[[Category:Virtualization]]&lt;/div&gt;</summary>
		<author><name>Mcrute</name></author>
	</entry>
</feed>