cmc/cleberg.net
My personal web garden & blog.
clone: git clone https://gitbay.org/cmc/cleberg.net.git
main: content/blog/2022-10-22-alpine-linux.org · raw
1#+date: [2022-10-22 Sat 00:00:00]
2#+title: Alpine Linux: Minimal Install, Minimal Attack Surface
3#+description: Installing Alpine Linux as a lightweight, secure server OS.
4#+slug: alpine-linux
5#+filetags: :linux:
6
7* Alpine Linux
8
9[[https://alpinelinux.org][Alpine Linux]] is a very small distribution, built on musl libc and busybox. It
10uses ash as the default shell, OpenRC as the init system, and apk as the package
11manager. According to their website, an Alpine container "requires no more than
128 megabytes (MB) and a minimal installation to disk requires around 130 MB of
13storage." An actual bare metal machine is recommended to have 100 MB of RAM and
140-700 MB of storage space.
15
16Historically, I've used Ubuntu's minimal installation image as my server OS for
17the last five years. Ubuntu worked well and helped as my original server
18contained an nVidia GPU (graphics processing unit) and no onboard graphics, so
19quite a few distributions won't boot or install without a lot of tinkering.
20
21Alpine has given me a huge increase in performance across my Docker apps and
22Nginx websites. CPU (central processing unit) load for the new server I'm using
23to test Alpine hovers around 0-5% on average with an Intel(R) Core(TM) i3-6100
24CPU @ 3.70 Gigahertz (GHz).
25
26The only services I haven't moved over to Alpine are Plex Media Server and
27Syncthing, which may increase CPU load quite a bit depending on how many streams
28are running.
29
30** Installation
31
32In terms of installation, Alpine has an incredibly useful [[https://wiki.alpinelinux.org/wiki/Installation][wiki]] that will guide a
33user throughout the installation and post-installation processes, as well as
34various other articles and guides.
35
36To install Alpine, find an appropriate [[https://alpinelinux.org/downloads/][image to download]] and flash it to a USB
37(Universal Serial Bus) using software such as Rufus or Etcher. I opted to use
38the Standard image for my x86_{64} architecture.
39
40Once the USB is ready, plug it into the machine and reboot. Note that you may
41have to use a key such as =Esc= or =F1-12= to access the boot menu. The Alpine
42Linux terminal will load quickly and for a login.
43
44To log in to the installation image, use the =root= account; there is no
45password. Once logged-in, execute the setup command:
46
47#+begin_src sh
48setup-alpine
49#+end_src
50
51The setup script will ask a series of questions to configure the system. Be sure
52to answer carefully or else you may have to re-configure the system after boot.
53
54- *Keyboard Layout*: Local keyboard language and usage mode, e.g., us and variant
55 of us-nodeadkeys.
56- *Hostname*: The name for the computer.
57- *Network*: For example, automatic internet protocol (IP) address discovery
58 with the Dynamic Host Configuration Protocol (DHCP) protocol.
59- *DNS (Domain Name System)*: DNS servers to query. For privacy reasons, it is
60 NOT recommended to route every local request to servers like Google's
61 8.8.8.8.
62- *Timezone
63- *Proxy*: Proxy server to use for accessing the web. Use =none= for direct
64 connections to the internet.
65- *Mirror*: From where to download packages. Choose the organization you trust
66 giving your usage patterns to.
67- *SSH (Secure Shell Protocol)*: Remote access server. =Openssh= is part of the
68 default install image. Use =none= to disable remote login, e.g. on laptops.
69- *NTP (Network Time Protocol)*: Client used for keeping the system clock in
70 sync with a time-server. Package =chrony= is part of the default install
71 image.
72- *Disk Mode*: Select between diskless (=none=), =data= or =sys=, as described
73 above.
74
75Once the setup script is finished, be sure to reboot the machine and remove the
76USB device.
77
78#+begin_src sh
79reboot
80#+end_src
81
82** Post-Installation
83
84There are many things you can do once your Alpine Linux system is up and
85running, and it largely depends on what you'll use the machine for. I'm going to
86walk through my personal post-installation setup for my web server.
87
881. Upgrade the System
89
90 First, login as =root= in order to update and upgrade the system:
91
92 #+begin_src sh
93 apk -U upgrade
94 #+end_src
95
962. Adding a User
97
98 I needed to add a user so that I don't need to log in as root. Note that if
99 you're used to using the =sudo= command, you will now need to use the =doas=
100 command on Alpine Linux.
101
102 #+begin_src sh
103 apk add doas
104 adduser <username>
105 adduser <username> wheel
106 #+end_src
107
108 You can now log out and log back in using the newly-created user:
109
110 #+begin_src sh
111 exit
112 #+end_src
113
1143. Enable Community Packages
115
116 In order to install more common packages that aren't found in the =main=
117 repository, you will need to enable the =community= repository:
118
119 #+begin_src sh
120 doas nano /etc/apk/repositories
121 #+end_src
122
123 Uncomment the community line for whichever version of Alpine you're running:
124
125 #+begin_src sh
126 /media/usb/apks
127 http://dl-cdn.alpinelinux.org/alpine/v3.16/main
128 http://dl-cdn.alpinelinux.org/alpine/v3.16/community
129 #http://dl-cdn.alpinelinux.org/alpine/edge/main
130 #http://dl-cdn.alpinelinux.org/alpine/edge/community
131 #http://dl-cdn.alpinelinux.org/alpine/edge/testing
132 #+end_src
133
1344. Install Required Packages
135
136 Now that the community packages are available, you can install any packages
137 you need. In my case, I installed the web server packages I need for my
138 services:
139
140 #+begin_src sh
141 doas apk add nano nginx docker docker-compose ufw
142 #+end_src
143
1445. SSH
145
146 If you didn't install OpenSSH as part of the installation, you can do so now:
147
148 #+begin_src sh
149 doas apk add openssh
150 #+end_src
151
152 Next, either create a new key or copy your SSH key to the server from your
153 current machines:
154
155 #+begin_src sh
156 # Create a new key
157 ssh-keygen
158 #+end_src
159
160 If you need to copy an existing SSH key from a current machine:
161
162 #+begin_src sh
163 # Copy key from existing machines
164 ssh-copy-id <username>@<ip_address>
165 #+end_src
166
1676. Firewall
168
169 Lastly, I installed =ufw= above as my firewall. To set up, default to deny
170 incoming and allow outgoing connections. Then selectively allow other ports
171 or apps as needed.
172
173 #+begin_src sh
174 doas ufw default deny incoming
175 doas ufw default allow outgoing
176 doas ufw allow SSH
177 doas ufw allow "WWW Full"
178 doas ufw allow 9418 # Git server port
179 #+end_src
180
1817. Change Hostname
182
183 If you don't like the hostname set during installation, you just need to edit
184 two files. First, edit the simple hostname file:
185
186 #+begin_src sh
187 doas nano /etc/hostname
188 #+end_src
189
190 #+begin_src sh
191 <hostname>
192 #+end_src
193
194 Next, edit the =hosts= file:
195
196 #+begin_src sh
197 doas nano /etc/hosts
198 #+end_src
199
200 #+begin_src sh
201 127.0.0.1 <hostname>.local <hostname> localhost.local localhost
202 ::1 <hostname> <hostname>.local
203 #+end_src
204
205* Nginx Web Server
206
207To set up my web server, I simply created the =www= user and created the
208necessary files.
209
210#+begin_src sh
211doas adduser -D -g 'www' www
212mkdir /www
213doas mkdir /www
214doas chown -R www:www /var/lib/nginx/
215doas chown -R www:www /www
216#+end_src
217
218If you're running a simple webroot, you can alter the main =nginx.conf= file.
219Otherwise, you can drop configuration files in the following directory. You
220don't need to enable or symlink the configuration file like you do in other
221systems.
222
223#+begin_src sh
224doas nano /etc/nginx/http.d/example_website.conf
225#+end_src
226
227Once the configuration is set and pointed at the =/www= directory to serve
228files, enable the Nginx service:
229
230#+begin_src sh
231# Note that 'default' must be included or Nginx will not start on boot
232doas rc-update add nginx default
233#+end_src
234
235* Docker Containers
236
237Docker works exactly the same as other systems. Either execute a =docker run=
238command or create a =docker-compose.yml= file and do =docker-compose up -d=.
239
240* Git Server
241
242I went in-depth on how to self-host a git server in another post: [[https://cleberg.net/blog/git-server.html][Self-Hosting
243Guide: Git & cGit]].
244
245However, there are a few differences with Alpine. First note that in order to
246change the =git= user's shell, you must do a few things a little different:
247
248#+begin_src sh
249doas apk add libuser
250doas touch /etc/login.defs
251doas mkdir /etc/default
252doas touch /etc/default/useradd
253doas lchsh git
254#+end_src
255
256* Thoughts on Alpine
257
258So far, I love Alpine Linux. I have no complaints about anything at this point,
259but I'm not completely finished with the migration yet. Once I'm able to upgrade
260my hardware to a rack-mounted server, I will migrate Plex and Syncthing over to
261Alpine as well - possibly putting Plex into a container or VM.
262
263The performance is stellar, the =apk= package manager is seamless, and system
264administration tasks are effortless. My only regret is that I didn't install
265Alpine sooner.