diff --git a/docs/dev/sw/imswitch/01_Quickstart.mdx b/docs/dev/sw/imswitch/01_Quickstart.mdx
index ddcb210d2..6300b3aac 100644
--- a/docs/dev/sw/imswitch/01_Quickstart.mdx
+++ b/docs/dev/sw/imswitch/01_Quickstart.mdx
@@ -22,7 +22,7 @@ The below diagramm visualizes the different modules that are connected to the op
## Getting Started
### Accessing ImSwitch
-Refer to our [usage guides](../../../usage/pro/frame/guides/day-1/sw-access/README.md#how-to-access-browser-apps).
+Refer to our [usage guides](../../../usage/pro/frame/guides/day-1/sw-access/README.md#browser-apps).
### Modifying ImSwitch Configuration
To adjust settings, edit the configuration file:
diff --git a/docs/usage/README.mdx b/docs/usage/README.mdx
index 0f27f5a2b..24170c414 100644
--- a/docs/usage/README.mdx
+++ b/docs/usage/README.mdx
@@ -6,6 +6,7 @@ sidebar_label: Overview
# Usage
Welcome to the openUC2 usage documentation! Here you'll find:
+
- **Hands-on tutorials** to help you learn how to do things with our products & projects
- **How-to guides** to help you accomplish practical goals with our products & projects
- **Reference** guides which you can consult for technical descriptions about our products & projects and how to use them
@@ -49,5 +50,6 @@ We also provide usage documentation for operating components included across var
- [Hikrobot Machine Vision Camera](./components/hik-camera/README.md)
- [ImSwitch](./components/imswitch/README.md)
+- [openUC2 OS](./components/os/README.md)
For documentation about how to develop functionalities with these components to do things beyond the off-the-shelf functionalities of openUC2 products, please see our [development documentation](../dev/README.md) instead.
diff --git a/docs/usage/components/os/README.md b/docs/usage/components/os/README.md
new file mode 100644
index 000000000..0c1cc8016
--- /dev/null
+++ b/docs/usage/components/os/README.md
@@ -0,0 +1 @@
+# openUC2 OS
diff --git a/docs/usage/components/os/configuration/README.md b/docs/usage/components/os/configuration/README.md
new file mode 100644
index 000000000..41136a02a
--- /dev/null
+++ b/docs/usage/components/os/configuration/README.md
@@ -0,0 +1,5 @@
+---
+sidebar_label: Configuration
+---
+
+# System Configuration
diff --git a/docs/usage/components/os/configuration/drop-in-files.md b/docs/usage/components/os/configuration/drop-in-files.md
new file mode 100644
index 000000000..deec738fc
--- /dev/null
+++ b/docs/usage/components/os/configuration/drop-in-files.md
@@ -0,0 +1,5 @@
+---
+sidebar_label: Drop-in Files
+---
+
+# Drop-in Configuration Files
diff --git a/docs/usage/components/os/networking/README.md b/docs/usage/components/os/networking/README.md
new file mode 100644
index 000000000..048579a4c
--- /dev/null
+++ b/docs/usage/components/os/networking/README.md
@@ -0,0 +1 @@
+# Networking
diff --git a/docs/usage/components/os/networking/firewall/README.md b/docs/usage/components/os/networking/firewall/README.md
new file mode 100644
index 000000000..fa6690c75
--- /dev/null
+++ b/docs/usage/components/os/networking/firewall/README.md
@@ -0,0 +1,155 @@
+# Firewall
+
+This reference guide describes the firewall system in openUC2 OS.
+
+openUC2 OS uses [firewalld](https://firewalld.org/documentation/) as its firewall.
+The firewall is run as the systemd service `firewalld.service`.
+
+firewalld is configured using openUC2 OS's pattern for [drop-in configuration files](../../configuration/drop-in-files.md).
+The drop-in configuration file system for firewalld is provided by Forklift package deployment `networking/firewalld`.
+
+## `firewalld.conf`
+
+Configuration variables in [`/etc/firewalld/firewalld.conf`](https://firewalld.org/documentation/configuration/firewalld-conf.html) are set with drop-in files in `/etc/firewalld/firewalld.conf.d`, which are controlled by Forklift package deployments and associated feature flags:
+
+| Setting | ...in drop-in file | ...from | ...is set by default? |
+| -------------------------------- | ------------------------------ | --------------------------------------------------- | --------------------- |
+| `DefaultZone`:
`public` | `20-default-zone.conf` | `networking/firewalld` | yes |
+| `StrictForwardPorts`:
`yes` | `20-strict-forward-ports.conf` | `networking/firewalld`:
`govern-docker-ports` | |
+
+`/etc/firewalld/firewalld.conf` is generated as follows:
+- The systemd service `assemble-firewalld-config.service` concatenates the contents of `/etc/firewalld/firewalld.conf.d/` and writes the output to `/run/overlays/generated/etc/firewalld/firewalld.conf`.
+- `/etc/firewalld/firewalld.conf` is a symlink to `/run/overlays/generated/etc/firewalld/firewalld.conf`.
+
+## Services
+
+firewalld is configured with the following [services](https://firewalld.org/documentation/service/), some of which are controlled by Forklift package deployments and associated feature flags:
+
+| Service | ...from | ...exists by default? |
+| -------------------- | --------------------------------------------------------------------------------------------- | --------------------- |
+| `dhcp` | firewalld | yes |
+| `dhcpv6` | firewalld | yes |
+| `dhcpv6-client` | firewalld | yes |
+| `dns` | firewalld | yes |
+| `mdns` | firewalld | yes |
+| `cockpit` | firewalld | yes |
+| `ssh` | firewalld | yes |
+| `http` | firewalld | yes |
+| `https` | firewalld | yes |
+| `http3` | firewalld | yes |
+| `http-untrusted` | `infra/caddy-ingress-untrusted`:
`firewall-allow-direct`,
`firewall-allow-public` | yes |
+| `esp32-ota-firmware` | `imswitch`:
`firewall-allow-direct`,
`firewall-allow-public` | yes |
+| `imswitch-dev` | `imswitch`:
`firewall-allow-direct`,
`firewall-allow-public` | yes |
+
+File locations:
+- Services from firewalld are defined in `/usr/lib/firewalld/services/`.
+- Services from Forklift package deployments are defined in `/etc/firewalld/services/`.
+
+These services expose the following ports:
+
+| Service | TCP Ports | UDP Ports |
+| -------------------- | ---------- | --------- |
+| `dhcp` | | 67 |
+| `dhcpv6` | | 547 |
+| `dhcpv6-client` | | 546 |
+| `dns` | 53 | 53 |
+| `mdns` | | 5353 |
+| `cockpit` | 9090 | |
+| `ssh` | 22 | |
+| `http` | 80 | |
+| `https` | 443 | |
+| `http3` | | 443 |
+| `http-untrusted` | 8000 | |
+| `esp32-ota-firmware` | 3333 | 3232 |
+| `imswitch-dev` | 8001, 8888 | |
+
+## Zones
+
+firewalld is configured with the following [zones](https://firewalld.org/documentation/zone/), which are controlled by Forklift package deployments and associated feature flags:
+
+| Zone | ...from | ...exists by default? |
+| ----------- | ------------------------------------------------------- | --------------------- |
+| `nm-shared` | `networking/firewalld`'s feature
`zone-nm-shared` | yes |
+| `public` | `networking/firewalld`'s feature
`zone-public` | yes |
+
+### `nm-shared`
+
+The `nm-shared` zone is intended to be used as the default firewall zone for NetworkManager connections with internet access sharing, such as direct connections to other devices.
+It is configured as a fully-privileged zone where unauthenticated administrative apps and services may be exposed.
+
+The `nm-shared` zone `/etc/firewalld/zones/nm-shared.xml` is defined by drop-in files in `/etc/firewalld/zones.d/nm-shared/`, which are controlled by Forklift package deployments and associated feature flags:
+
+| Setting | ...in drop-in file | ...from | ...is set by default? |
+| --------------------------------------- | --------------------------------------- | --------------------------------------------------------------------- | --------------------- |
+| interface
`tailscale0` | `20-interface-tailscale0.xml` | `networking/tailscale`:
`firewall-as-direct` | yes |
+| protocol
`icmp` | `30-protocol-icmp.xml` | `networking/networkmanager/base`:
`firewall-allow-direct` | yes |
+| protocol
`ipv6-icmp` | `30-protocol-icmp.xml` | `networking/networkmanager/base`:
`firewall-allow-direct` | yes |
+| service
`dhcp` | `40-service-dhcp.xml` | `networking/networkmanager/base`:
`firewall-allow-direct` | yes |
+| service
`dhcpv6` | `40-service-dhcp.xml` | `networking/networkmanager/base`:
`firewall-allow-direct` | yes |
+| service
`dhcpv6-client` | `40-service-dhcp.xml` | `networking/networkmanager/base`:
`firewall-allow-direct` | yes |
+| service
`dns` | `40-service-dns.xml` | `networking/networkmanager/base`:
`firewall-allow-direct` | yes |
+| service
`mdns` | `40-service-mdns.xml` | `networking/avahi/daemon`:
`firewall-allow-direct` | yes |
+| service
`cockpit` | `50-service-cockpit.xml` | `admin/cockpit`:
`firewall-allow-direct` | yes |
+| service
`ssh` | `50-service-ssh.xml` | `admin/sshd`:
`firewall-allow-direct` | yes |
+| service
`http` | `60-service-http.xml` | `infra/caddy-ingress`:
`firewall-allow-direct` | yes |
+| service
`https` | `60-service-https.xml` | `infra/caddy-ingress`:
`firewall-allow-direct` | yes |
+| service
`http3` | `60-service-http3.xml` | `infra/caddy-ingress`:
`firewall-allow-direct` | yes |
+| service
`http-untrusted` | `60-service-http-untrusted.xml` | `infra/caddy-ingress-untrusted`:
`firewall-allow-direct` | yes |
+| service
`esp32-ota-firmware` | `70-service-esp32-ota-firmware.xml` | `imswitch`:
`firewall-allow-direct` | yes |
+| service
`imswitch-dev` | `70-service-imswitch-dev.xml` | `imswitch`:
`firewall-allow-direct` | yes |
+| rule (priority 32767)
reject | `90-rule-default.xml` | `networking/firewalld` | yes |
+
+Naming conventions:
+- The numeric prefixes of any additional rules should be at least `20` and less than `90`.
+ - The prefix `20-` is used for binding interfaces to the zone.
+ - The prefix `30-` is used for low-level networking protocols.
+ - The prefix `40-` is used for networking protocols which facilitate device connectivity & access.
+ - The prefix `50-` is used for administrative services.
+ - The prefix `60-` is used for general/infrastructural application services.
+ - The prefix `70-` is used for specific applications.
+- Feature flags configuring firewalld to allow access to ports should be named `firewall-allow-direct`.
+
+`/etc/firewalld/zones/nm-shared.xml` is generated as follows:
+- The systemd service `assemble-firewalld-config.service` concatenates the contents of `/etc/firewalld/zones.d/nm-shared/` and writes the output to `/run/overlays/generated/etc/firewalld/zones/nm-shared.xml`.
+- `/etc/firewalld/zones/nm-shared.xml` is a symlink to `/run/overlays/generated/etc/firewalld/zones/nm-shared.xml`.
+
+### `public`
+
+The `public` zone is intended to be used as the default firewall zone for connections by untrusted strangers.
+It is configured as an unprivileged zone.
+
+The `public` zone `/etc/firewalld/zones/public.xml` is defined by drop-in files in `/etc/firewalld/zones.d/public/`, which are controlled by Forklift package deployments and associated feature flags:
+
+| Setting | ...in drop-in file | ...from | ...is set by default? |
+| --------------------------------------- | --------------------------------------- | --------------------------------------------------------------------- | --------------------- |
+| interface
`tailscale0` | `20-interface-tailscale0.xml` | `networking/tailscale`:
`firewall-as-public` | |
+| protocol
`icmp` | `30-protocol-icmp.xml` | `networking/networkmanager/base`:
`firewall-allow-public` | yes |
+| protocol
`ipv6-icmp` | `30-protocol-icmp.xml` | `networking/networkmanager/base`:
`firewall-allow-public` | yes |
+| service
`dhcp` | `40-service-dhcp.xml` | `networking/networkmanager/base`:
`firewall-allow-public` | yes |
+| service
`dhcpv6` | `40-service-dhcp.xml` | `networking/networkmanager/base`:
`firewall-allow-public` | yes |
+| service
`dhcpv6-client` | `40-service-dhcp.xml` | `networking/networkmanager/base`:
`firewall-allow-public` | yes |
+| service
`dns` | `40-service-dns.xml` | `networking/networkmanager/base`:
`firewall-allow-public` | yes |
+| service
`mdns` | `40-service-mdns.xml` | `networking/avahi/daemon`:
`firewall-allow-public` | yes |
+| service
`cockpit` | `50-service-cockpit.xml` | `admin/cockpit`:
`firewall-allow-public` | yes |
+| service
`ssh` | `50-service-ssh.xml` | `admin/sshd`:
`firewall-allow-public` | yes |
+| service
`http` | `60-service-http.xml` | `infra/caddy-ingress`:
`firewall-allow-public` | |
+| service
`https` | `60-service-https.xml` | `infra/caddy-ingress`:
`firewall-allow-public` | |
+| service
`http3` | `60-service-http3.xml` | `infra/caddy-ingress`:
`firewall-allow-public` | |
+| service
`http-untrusted` | `60-service-http-untrusted.xml` | `infra/caddy-ingress-untrusted`:
`firewall-allow-public` | yes |
+| forward `:80` to
`127.0.0.1:8000` | `70-forward-http-to-http-untrusted.xml` | `infra/caddy-ingress-untrusted`:
`firewall-forward-http-public` | yes |
+| service
`esp32-ota-firmware` | `70-service-esp32-ota-firmware.xml` | `imswitch`:
`firewall-allow-public` | yes |
+| service
`imswitch-dev` | `70-service-imswitch-dev.xml` | `imswitch`:
`firewall-allow-public` | yes |
+
+Naming conventions:
+- The numeric prefixes of any additional rules should be at least `20` and less than `90`.
+ - The prefix `20-` is used for binding interfaces to the zone.
+ - The prefix `30-` is used for low-level networking protocols.
+ - The prefix `40-` is used for networking protocols which facilitate device connectivity & access.
+ - The prefix `50-` is used for administrative services.
+ - The prefix `60-` is used for general/infrastructural application services.
+ - The prefix `70-` is used for specific applications.
+- Feature flags configuring firewalld to allow access to ports should be named `firewall-allow-public`.
+
+`/etc/firewalld/zones/public.xml` is generated as follows:
+- The systemd service `assemble-firewalld-config.service` concatenates the contents of `/etc/firewalld/zones.d/public/` and writes the output to `/run/overlays/generated/etc/firewalld/zones/public.xml`.
+- `/etc/firewalld/zones/public.xml` is a symlink to `/run/overlays/generated/etc/firewalld/zones/public.xml`.
diff --git a/docs/usage/pro/frame/guides/day-1/connectivity/README.md b/docs/usage/pro/frame/guides/day-1/connectivity/README.md
index 185c5ea3e..312060cd3 100644
--- a/docs/usage/pro/frame/guides/day-1/connectivity/README.md
+++ b/docs/usage/pro/frame/guides/day-1/connectivity/README.md
@@ -7,8 +7,8 @@ toc_max_heading_level: 4
# Machine Connectivity
The how-to guides here will help you to:
-- access your FRAME's software
-- make your FRAME's software easy to access
+- connect to your FRAME, so that you can [access its software](../sw-access/README.md)
+- make your FRAME's software easy to connect to
This process will be less stressful for you if you've already done [the relevant day-0 planning](../../day-0/connectivity/README.md).
@@ -46,7 +46,7 @@ To choose which of the following methods you will use for connecting to the FRAM
1. On your computer, connect to the FRAME's Wi-Fi hotspot.
- :::tip
+ :::info
By default, the Wi-Fi hotspot's name is `openuc2-{machine name}`, where `{machine name}` is your FRAME's machine name.
For example, if your FRAME's machine name is `great-example-1234`, then the Wi-Fi hotspot's name is `openuc2-great-example-1234`.
@@ -58,6 +58,7 @@ To choose which of the following methods you will use for connecting to the FRAM
:::tip
By default, the Wi-Fi hotspot's password is `youseetoo`.
+ You should [change it to a more secure password](../security/README.md#how-to-change-the-wi-fi-hotspots-password).
:::
@@ -79,6 +80,12 @@ To choose which of the following methods you will use for connecting to the FRAM
1. Connect your FRAME to a Local Area Network (LAN) by following the same procedure you would use to [connect your FRAME to the internet](#how-to-connect-the-frame-to-the-internet) via a network router or external Wi-Fi network.
2. Connect your computer to the same LAN.
+:::tip
+
+If you intend to access administrative apps over the LAN, you will need to explicitly [allow access to unauthenticated administrative apps over the LAN](../sw-access/README.md#to-unauthenticated-administrative-apps-over-local-area-networks).
+
+:::
+
## How to access the FRAME's landing page
The following factors will determine which access methods work for you:
diff --git a/docs/usage/pro/frame/guides/day-1/security/README.md b/docs/usage/pro/frame/guides/day-1/security/README.md
new file mode 100644
index 000000000..3b59454c5
--- /dev/null
+++ b/docs/usage/pro/frame/guides/day-1/security/README.md
@@ -0,0 +1,160 @@
+---
+sidebar_position: 30
+toc_max_heading_level: 4
+---
+
+# Security
+
+Because your FRAME includes an embedded computer which comes with some default settings which make it less secure and easier to access for initial deployment & setup, the how-to guides here will help you override these default settings in order to:
+
+- reduce your FRAME's exposure to unauthorized access
+- limit the potential impact of any security breaches
+
+## Connectivity
+
+### How to change the Wi-Fi hotspot's password
+
+By default, the password used for [connecting to the FRAME's Wi-Fi hotspot](../connectivity/README.md#via-the-frames-wi-fi-hotspot) is `youseetoo`.
+You should change this password to something more secure:
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the following command and follow the displayed instructions:
+ ```bash
+ read -sp "Enter a new password: " password && echo "psk=$password" | sudo tee >/dev/null \
+ /etc/NetworkManager/system-connections.d/wlan0-hotspot/51-wifi-security-password.nmconnection
+ ```
+3. Apply your changes by rebooting or running the following commands:
+ ```bash
+ sudo systemctl restart \
+ assemble-networkmanager-connection-templated@wlan0-hotspot.service \
+ assemble-networkmanager-connection@wlan0-hotspot.service
+ sudo nmcli conn reload
+ ```
+
+## Software Access
+
+### How to change the `pi` user's password
+
+By default, the `pi` user's password is `youseetoo`, and it's used for:
+
+- [accessing the RPi's terminal via Cockpit](../sw-access/README.md#via-cockpit)
+- [accessing the RPi's terminal via SSH](../sw-access/README.md#via-ssh)
+- running `sudo` commands in the RPi's terminal
+
+You should change this password to something more secure.
+
+:::warning
+
+**PLEASE** change this password if you choose not to [block access to Cockpit](#to-cockpit) and [to SSH](#to-ssh) over Local Area Networks!
+Otherwise, anyone on the same network as your RPi may be able to do anything they want to your RPi by logging in as the `pi` user with the password `youseetoo`.
+
+:::
+
+#### via Cockpit
+
+1. [Open Cockpit](../sw-access/README.md#cockpit).
+2. Open the "Accounts" page using Cockpit's navigation sidebar.
+3. Click on the "pi" username to open the page for editing the `pi` user.
+4. Click on the "Set password" button.
+5. Enter the `pi` user's current password in the "Old password" text box, enter your desired password for the `pi` user in the "New password" and "Confirm new password" boxes, and then click on the "Set password" button.
+
+#### via the terminal
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the command `passwd` and follow the displayed instructions.
+
+### How to block access over Local Area Networks (LANs)
+
+#### to Cockpit
+
+To prevent Cockpit from being accessible by any other device on the same LAN as your RPi:
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the command:
+ ```bash
+ forklift plt disable-depl-feat --stage admin/cockpit firewall-allow-public frontend-untrusted
+ ```
+3. Apply your changes by rebooting.
+
+To undo your changes:
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the command:
+ ```bash
+ forklift plt enable-depl-feat --stage admin/cockpit firewall-allow-public frontend-untrusted
+ ```
+3. Apply your changes by rebooting.
+
+#### to SSH
+
+To prevent your RPi from being accessible over SSH from any other device on the same LAN:
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the command:
+ ```bash
+ forklift plt disable-depl-feat --stage admin/sshd firewall-allow-public
+ ```
+3. Apply your changes by rebooting.
+
+To undo your changes:
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the command:
+ ```bash
+ forklift plt enable-depl-feat --stage admin/sshd firewall-allow-public
+ ```
+3. Apply your changes by rebooting.
+
+### How to control access to unauthenticated administrative apps over Tailscale
+
+By default, the firewall is configured to bind Tailscale to firewalld's `nm-shared` zone for trusted networks like the RPi's Wi-Fi hotspot. You can instead change the firewall to bind Tailscale to the default zone, `public`, so that it will be treated like any other untrusted Local Area Network:
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the command:
+ ```bash
+ forklift plt disable-depl-feat networking/tailscale firewall-zone-nm-shared
+ forklift plt stage
+ ```
+3. Apply your changes by rebooting.
+
+Afterwards, access to unauthenticated administrative apps (such as the Machine Administration app, Dozzle, and the system file manager) will only be possible if you explicitly [allow such access over Local Area Networks](../sw-access/README.md#to-unauthenticated-administrative-apps-over-local-area-networks).
+
+To undo your changes:
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the command:
+ ```bash
+ forklift plt enable-depl-feat networking/tailscale firewall-zone-nm-shared
+ forklift plt stage
+ ```
+3. Apply your changes by rebooting.
+
+### How to prevent Docker's port-forwarding from bypassing firewall rules
+
+Docker containers which forward ports to `0.0.0.0`/`[::]` (instead of forwarding ports to a particular IP address such as `127.0.0.1`) will bypass all firewall rules and be accessible on all network interfaces.
+To only allow a forwarded ports to be accessible (in all firewalld zones) when a port-forwarding firewall rule exists for that port (in any firewalld zone):
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the command:
+ ```bash
+ forklift plt enable-depl-feat networking/firewalld govern-docker-ports
+ forklift plt stage
+ ```
+3. Apply your changes by rebooting.
+
+:::warning
+
+When any firewalld zone has port-forwarding rule to allow a Docker-forwarded port, that Docker-forwarded port will be accessible in **all** firewalld zones regardless of the configuration those other zones.
+This appears to be a consequence of how Docker implements port forwarding.
+
+:::
+
+To undo your changes:
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the command:
+ ```bash
+ forklift plt disable-depl-feat networking/firewalld govern-docker-ports
+ forklift plt stage
+ ```
+3. Apply your changes by rebooting.
diff --git a/docs/usage/pro/frame/guides/day-1/sw-access/README.md b/docs/usage/pro/frame/guides/day-1/sw-access/README.md
index 7a44a235e..b9f44bc5c 100644
--- a/docs/usage/pro/frame/guides/day-1/sw-access/README.md
+++ b/docs/usage/pro/frame/guides/day-1/sw-access/README.md
@@ -4,7 +4,14 @@ sidebar_position: 21
# Software Access
-## How to access browser apps
+The how-to guides here will help you to:
+- access your FRAME's graphical interfaces using your web browser
+- use your FRAME's command-line interface over SSH
+- allow access to your FRAME's software from more devices
+
+## How to access
+
+### browser apps
1. [Connect to the FRAME](../connectivity/README.md#how-to-connect-to-the-frame).
@@ -13,25 +20,55 @@ sidebar_position: 21
3. Click on the link for the browser app.
For example, to open ImSwitch, click on the landing page's link for ImSwitch.
-## How to access the FRAME's terminal
+ If the browser app doesn't load and you're indirectly connected to the FRAME [via a Local Area Network](../connectivity/README.md#via-a-local-area-network), then you must add port 8000 to the URL in your address bar.
+ For example, if the landing page's link for ImSwitch opened [openuc2.local/imswitch/ui/index.html](http://openuc2.local/imswitch/ui/index.html), then you should instead open [openuc2.local:8000/imswitch/ui/index.html](http://openuc2.local:8000/imswitch/ui/index.html).
+ Note that administrative apps cannot be used on port 8000.
+
+ :::tip
+
+ You can also open the FRAME's landing page on port 8000.
+ For example, if you use [openuc2.local](http://openuc2.local), then you can open [openuc2.local:8000](http://openuc2.local:8000)
-### via Cockpit
+ :::
+
+### Cockpit
-1. [Open the browser app](#how-to-access-browser-apps) for Cockpit.
+1. [Open the browser app](#browser-apps) for Cockpit.
2. Log in to Cockpit, using the `pi` username and the password for the `pi` user.
:::tip
By default, the `pi` user's password is `youseetoo`.
+ You should [change it to a more secure password](../security/README.md#how-to-change-the-pi-users-password).
:::
-3. Open the Terminal using Cockpit's navigation sidebar.
+If something has gone wrong with the operating system, you may be able to access Cockpit through its direct-access fallback instead:
+
+1. [Connect to the FRAME](../connectivity/README.md#how-to-connect-to-the-frame).
+
+2. In your computer's web browser, enter the URL for [the FRAME's landing page](../connectivity/README.md#how-to-access-the-frames-landing-page), but append `:9090/admin/cockpit/` to it.
+ For example, if you would normally open the landing page at [http://openuc2.local](http://openuc2.local), then you should instead open [http://openuc2.local:9090/admin/cockpit/](http://openuc2.local:9090/admin/cockpit/).
-### via SSH
+ :::info
-If you're able to [access the landing page](../connectivity/README.md#how-to-access-the-frames-landing-page) via the URL `http://{domain name}`, then:
+ The trailing slash in `:9090/admin/cockpit/` is absolutely necessary!
+ only typing `:9090/admin/cockpit` will give you an error message.
+
+ :::
+
+### the FRAME's terminal
+
+#### via Cockpit
+
+1. [Open Cockpit](#cockpit).
+
+2. Open the Terminal using Cockpit's navigation sidebar.
+
+#### via SSH
+
+If you would normally [access the landing page](../connectivity/README.md#how-to-access-the-frames-landing-page) via the URL `http://{domain name}`, then:
1. Open a local terminal on your computer.
@@ -43,5 +80,57 @@ If you're able to [access the landing page](../connectivity/README.md#how-to-acc
:::tip
By default, the `pi` user's password is `youseetoo`.
+ You should [change it to a more secure password](../security/README.md#how-to-change-the-pi-users-password).
:::
+
+## How to allow access
+
+### to unauthenticated administrative apps over Local Area Networks
+
+For security reasons, by default the FRAME is configured to block access [over Local Area Networks (LAN)](../connectivity/README.md#via-a-local-area-network) to browser apps (such as the Machine Administration app, Dozzle, and the system file manager) which can perform administrative operations without user authentication. You can override this default behavior to allow access to those apps over LANs:
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the commands:
+ ```bash
+ forklift plt disable-depl-feat infra/caddy-ingress-untrusted firewall-forward-http-public
+ forklift plt enable-depl-feat infra/caddy-ingress firewall-allow-public
+ forklift plt stage
+ ```
+3. Apply your changes by rebooting.
+
+:::danger
+
+This could allow anyone on the same LAN to do whatever they want with your FRAME!
+You should ensure that your LAN has its own firewall settings to prevent people you don't trust from using the LAN to access your FRAME over port 80.
+
+:::
+
+To undo this change:
+1. Run the commands:
+ ```bash
+ forklift plt enable-depl-feat infra/caddy-ingress-untrusted firewall-forward-http-public
+ forklift plt disable-depl-feat infra/caddy-ingress firewall-allow-public
+ forklift plt stage
+ ```
+2. Apply your changes by rebooting.
+
+### to Cockpit from non-standard origins
+
+For security reasons, Cockpit only allows logins from explicitly-specified origins (in `{protocol}{domain name or IP address}{port}` form, e.g. `http://my.domain.tld` or `http://my.domain.tld:9090` or `https://10.196.250.1`). To add another origin `{origin}` to Cockpit's list of allowed origins:
+
+1. [Enter the RPi's terminal](../sw-access/README.md#the-frames-terminal).
+2. Run the following command:
+ ```bash
+ sudo tee -a <<<'{origin}' /etc/cockpit/origins.d/80-custom-origins
+ ```
+ For example, to allow logins from `http://my.domain.tld:9090`, run:
+ ```bash
+ sudo tee -a <<<'http://my.domain.tld:9090' /etc/cockpit/origins.d/80-custom-origins
+ ```
+3. Apply your changes by rebooting or running the following commands:
+ ```bash
+ sudo systemctl restart \
+ assemble-cockpit-origins.service \
+ assemble-cockpit-config.service
+ ```
diff --git a/docs/usage/pro/frame/guides/troubleshooting/logging.md b/docs/usage/pro/frame/guides/troubleshooting/logging.md
index 50f924671..4a0384c55 100644
--- a/docs/usage/pro/frame/guides/troubleshooting/logging.md
+++ b/docs/usage/pro/frame/guides/troubleshooting/logging.md
@@ -39,7 +39,7 @@ To undo this change:
After [enabling persistent logging](#how-to-enable-persistent-logging):
-1. Enter the RPi's terminal.
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
2. Run the command `journalctl --boot=-{n}` to check the logs from `n` boots ago.
For example, run `journalctl --boot=-1` to check the logs from the previous boot.
diff --git a/docs/usage/pro/frame/guides/troubleshooting/networking.md b/docs/usage/pro/frame/guides/troubleshooting/networking.md
deleted file mode 100644
index bcd1b21b2..000000000
--- a/docs/usage/pro/frame/guides/troubleshooting/networking.md
+++ /dev/null
@@ -1,100 +0,0 @@
----
-toc_max_heading_level: 4
----
-
-# Networking
-
-## Firewall
-
-### How to disable the firewall
-
-#### temporarily
-
-To disable the firewall until the next boot:
-
-1. Enter the RPi's terminal.
-2. Run the command `sudo systemctl stop firewalld`.
-
-To undo this change:
-
-1. Enter the RPi's terminal.
-2. Run the command `sudo systemctl start firewalld`.
-
-#### persistently
-
-To disable the firewall on every boot:
-
-1. Enter the RPi's terminal.
-2. Run the command `sudo systemctl disable --now firewalld`.
-3. Run the command `sudo systemctl mask firewalld`.
-
-To undo this change:
-
-1. Enter the RPi's terminal.
-2. Run the command `sudo systemctl enable --now firewalld`.
-3. Run the command `sudo systemctl unmask firewalld`.
-
-### How to open a new port
-
-#### temporarily
-
-To open up a new TCP port `{port}`:
-
-1. Enter the RPi's terminal.
-2. Run the command:
- ```bash
- sudo firewall-cmd --zone=public --add-port={port}/tcp
- sudo firewall-cmd --zone=nm-shared --add-port={port}/tcp
- ```
- For example, to open up TCP port 8080, run:
- ```bash
- sudo firewall-cmd --zone=public --add-port=8080/tcp
- sudo firewall-cmd --zone=nm-shared --add-port=8080/tcp
- ```
-
-#### persistently
-
-To open up a new TCP port `{port}`:
-
-1. Enter the RPi's terminal.
-2. Run the following command:
- ```bash
- sudo tee -a <<<' ' \
- /etc/firewalld/zones.d/public/80-custom-ports.xml \
- /etc/firewalld/zones.d/nm-shared/80-custom-ports.xml
- ```
- For example, to open up TCP port 8080, run:
- ```bash
- sudo tee -a <<<' ' \
- /etc/firewalld/zones.d/public/80-custom-ports.xml \
- /etc/firewalld/zones.d/nm-shared/80-custom-ports.xml
- ```
-3. Apply your changes by rebooting or running the following commands:
- ```bash
- sudo systemctl restart \
- assemble-firewalld-zone@public.service \
- assemble-firewalld-zone@nm-shared.service
- sudo firewall-cmd --reload
- ```
-
-To undo this change:
-1. Enter the RPi's terminal.
-2. Run the following command:
- ```bash
- sudo sed -i '//d' \
- /etc/firewalld/zones.d/public/80-custom-ports.xml \
- /etc/firewalld/zones.d/nm-shared/80-custom-ports.xml
- ```
- For example, to undo the opening of TCP port 8080, run:
- ```bash
- sudo sed -i '//d' \
- /etc/firewalld/zones.d/public/80-custom-ports.xml \
- /etc/firewalld/zones.d/nm-shared/80-custom-ports.xml
- ```
-3. Apply your changes by rebooting or running the following commands:
- ```bash
- sudo systemctl restart \
- assemble-firewalld-zone@public.service \
- assemble-firewalld-zone@nm-shared.service
- sudo firewall-cmd --reload
- ```
diff --git a/docs/usage/pro/frame/guides/troubleshooting/sw-access.md b/docs/usage/pro/frame/guides/troubleshooting/sw-access.md
new file mode 100644
index 000000000..46badd7ee
--- /dev/null
+++ b/docs/usage/pro/frame/guides/troubleshooting/sw-access.md
@@ -0,0 +1,310 @@
+---
+toc_max_heading_level: 4
+---
+
+# Software Access
+
+The how-to guides here will help you to determine why you can't access a particular software program which is supposed to be running in openUC2 OS.
+
+## How to troubleshoot an inaccessible network service
+
+1. If the network service is deployed as a Docker container, [check the status of its Docker container(s)](#how-to-check-docker-container-status).
+
+ Otherwise, if the network service is deployed as a systemd service, [check the status of its systemd service(s)](#how-to-check-systemd-service-status).
+
+3. If the network service is supposed to be accessed via port 80, 443, or 8000, check whether other network services (e.g. ImSwitch, the openUC2 offline documentation, and the system file manager) are available over those ports by [opening their browser apps](../day-1/sw-access/README.md#browser-apps).
+
+4. If the network service binds directly to a port on the RPi, [check the network port bindings](#how-to-check-network-port-bindings) to determine whether the network service is bound to its expected port.
+
+ If not the network service is not bound to its expected port, check whether some other network service is already bound to the network port.
+
+5. Check whether the network service is accessible over a local connection from within the RPi (i.e. as `localhost`).
+
+6. [Check the firewall settings](#how-to-check-firewall-settings) on the RPi to determine whether the firewall is configured to make the network service (and any network ports which it binds to) accessible over external network connections.
+
+ If not, [open the port in the firewall](#how-to-open-a-new-firewall-port).
+ If opening the firewall port doesn't seem to help, then check whether [disabling the firewall](#how-to-disable-the-firewall) makes the port accessible.
+ If the port becomes accessible after disabling the firewall, then you have not correctly opened the port in the firewall.
+
+## How to check Docker container status
+
+### via Dozzle
+
+1. [Open the browser app](../day-1/sw-access/README.md#browser-apps) for Dozzle.
+2. If the Docker container does not appear in the sidebar's list of running containers, then either the container has stopped or it never started.
+ In that case, open the settings menu in the sidebar; if the "Show All Containers" menu item doesn't show a checked checkbox to indicate that it's enabled, click on that menu item to make Dozzle show all containers. If the Docker container then appears with a red circle, then the container has stopped.
+3. Click on the container in the sidebar to see its logs.
+
+### via the terminal
+
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+
+2. To see the names and statuses of all containers, run the command:
+ ```bash
+ docker ps -a
+ ```
+
+ :::tip
+
+ Command-line options are described in the the `docker ps` command's [documentation](https://docs.docker.com/reference/cli/docker/container/ls/).
+
+ :::
+
+3. To see the logs of a container with name `{name}`, run the command:
+ ```bash
+ docker logs {name}
+ ```
+ For example, to see the logs of container `infra_caddy-ingress-http-1`, run the command:
+ ```bash
+ docker logs infra_caddy-ingress-http-1
+ ```
+
+ :::tip
+
+ Command-line options are described in the the `docker logs` command's [documentation](https://docs.docker.com/reference/cli/docker/container/logs/).
+
+ :::
+
+## How to check systemd service status
+
+### via Cockpit
+
+1. [Open Cockpit](../day-1/sw-access/README.md#cockpit).
+2. If Cockpit's top menubar displays a yellow lock icon with the label "Limited access", click on it to enable administrative access.
+3. Open the "Services" page using Cockpit's navigation sidebar.
+4. Click on the entry for the service.
+
+### via the terminal
+
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+2. To see the status of a service with name `{name}.service`, run the command:
+ ```bash
+ systemctl status {name}.service
+ ```
+ For example, to see the status of service `ssh.service`, run the command:
+ ```bash
+ systemctl status ssh.service
+ ```
+
+ :::tip
+
+ Command-line options are described in the the `systemctl status` command's [documentation](https://www.freedesktop.org/software/systemd/man/latest/systemctl.html#status%20PATTERN%E2%80%A6%7CPID%E2%80%A6%5D).
+
+ :::
+
+3. To see the logs of the service with name `{name}.service`, run the command:
+ ```bash
+ journalctl -u {name}.service
+ ```
+ For example, to see the logs of service `ssh.service`, run the command:
+ ```bash
+ journalctl -u ssh.service
+ ```
+
+ :::tip
+
+ Command-line options are described in the the `journalctl` command's [documentation](https://www.freedesktop.org/software/systemd/man/latest/journalctl.html).
+
+ :::
+
+## How to check network port bindings
+
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+2. Run the command:
+ ```bash
+ sudo netstat -tulpn
+ ```
+
+ :::tip
+
+ Command-line options are described in the the `netstat` command's [documentation](https://manpages.debian.org/stable/net-tools/netstat.8.en.html).
+
+ :::
+
+## How to check firewall settings
+
+### via Cockpit
+
+1. [Open Cockpit](../day-1/sw-access/README.md#cockpit).
+2. If Cockpit's top menubar displays a yellow lock icon with the label "Limited access", click on it to enable administrative access.
+3. Open the "Networking" page using Cockpit's navigation sidebar.
+4. In the "Firewall" page, click on the "Edit rules and zones" button.
+
+### via the terminal
+
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+2. Run the commands:
+ ```bash
+ sudo firewall-cmd --list-all --zone=public
+ sudo firewall-cmd --list-all --zone=nm-shared
+ ```
+
+ :::tip
+
+ Command-line options are described in the the `firewall-cmd` command's [documentation](https://firewalld.org/documentation/man-pages/firewall-cmd.html).
+
+ :::
+
+## How to open a new firewall port
+
+### temporarily
+
+#### via Cockpit
+
+1. [Open Cockpit](../day-1/sw-access/README.md#cockpit).
+2. If Cockpit's top menubar displays a yellow lock icon with the label "Limited access", click on it to enable administrative access.
+3. Open the "Networking" page using Cockpit's navigation sidebar.
+4. In the "Firewall" page, click on the "Edit rules and zones" button.
+5. If the port needs to be accessible over [direct connections to the FRAME](../day-1/connectivity/README.md#directly), add a firewalld service for the port in the "NetworkManager Shared" zone:
+ 1. In the "NetworkManager Shared zone" section, click on the "Add services" button to create a new firewalld service.
+ 2. In the resulting modal dialogue, either:
+ - Click on the "Services" radio button, select a known service associated with the port, and then click on the "Add services" button; or
+ - Click on the "Custom ports" radio button, enter the requested information, and then click on the "Add ports" button.
+6. If the port needs to be accessible over indirect connections to the FRAME [via a Local Area Network](../day-1/connectivity/README.md#via-a-local-area-network), add a firewall service for the port in the "Public" zone:
+ 1. In the "Public zone" section, click on the "Add services" button to create a new firewalld service.
+ 2. In the resulting modal dialogue, either:
+ - Click on the "Services" radio button, select a known service associated with the port, and then click on the "Add services" button; or
+ - Click on the "Custom ports" radio button, enter the requested information, and then click on the "Add ports" button.
+
+#### via the terminal
+
+To open up a new TCP port `{port}`:
+
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+2. Run the commands:
+ ```bash
+ sudo firewall-cmd --zone=public --add-port={port}/tcp
+ sudo firewall-cmd --zone=nm-shared --add-port={port}/tcp
+ ```
+ For example, to open up TCP port 8080, run:
+ ```bash
+ sudo firewall-cmd --zone=public --add-port=8080/tcp
+ sudo firewall-cmd --zone=nm-shared --add-port=8080/tcp
+ ```
+
+ :::tip
+
+ Command-line options are described in the the `firewall-cmd` command's [documentation](https://firewalld.org/documentation/man-pages/firewall-cmd.html).
+
+ :::
+
+### persistently
+
+To open up a new port `{port}` in protocol `{protocol}`:
+
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+2. If the port needs to be accessible over [direct connections to the FRAME](../day-1/connectivity/README.md#directly), add a rule for the port in the "nm-shared" zone:
+ 1. Run the following command:
+ ```bash
+ sudo tee -a <<<' ' \
+ /etc/firewalld/zones.d/nm-shared/80-custom-ports.xml
+ ```
+ For example, to open up TCP port 8080, run:
+ ```bash
+ sudo tee -a <<<' ' \
+ /etc/firewalld/zones.d/nm-shared/80-custom-ports.xml
+ ```
+3. If the port needs to be accessible over indirect connections to the FRAME [via a Local Area Network](../day-1/connectivity/README.md#via-a-local-area-network), add a rule for the port in the "public" zone:
+ 1. Run the following command:
+ ```bash
+ sudo tee -a <<<' ' \
+ /etc/firewalld/zones.d/public/80-custom-ports.xml
+ ```
+ For example, to open up TCP port 8080, run:
+ ```bash
+ sudo tee -a <<<' ' \
+ /etc/firewalld/zones.d/public/80-custom-ports.xml
+ ```
+4. Apply your changes by rebooting or running the following commands:
+ ```bash
+ sudo systemctl restart \
+ assemble-firewalld-zone@public.service \
+ assemble-firewalld-zone@nm-shared.service
+ sudo firewall-cmd --reload
+ ```
+
+:::info
+
+`firewall-cmd`'s `--permanent` and `--runtime-to-permanent` options do not persist firewall configuration changes in openUC2 OS.
+Instead, you **must** create files in openUC2 OS's drop-in configuration directories at `/etc/firewalld/zones.d/{zone name}`, as shown above.
+
+:::
+
+To undo this change:
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+2. Run the following command:
+ ```bash
+ sudo sed -i '//d' \
+ /etc/firewalld/zones.d/public/80-custom-ports.xml \
+ /etc/firewalld/zones.d/nm-shared/80-custom-ports.xml
+ ```
+ For example, to undo the opening of TCP port 8080, run:
+ ```bash
+ sudo sed -i '//d' \
+ /etc/firewalld/zones.d/public/80-custom-ports.xml \
+ /etc/firewalld/zones.d/nm-shared/80-custom-ports.xml
+ ```
+3. Apply your changes by rebooting or running the following commands:
+ ```bash
+ sudo systemctl restart \
+ assemble-firewalld-zone@public.service \
+ assemble-firewalld-zone@nm-shared.service
+ sudo firewall-cmd --reload
+ ```
+
+## How to disable the firewall
+
+:::danger
+
+If your FRAME is connected to a Local Area Network (e.g. for internet access), this could allow anyone on the same network to do whatever they want with your FRAME!
+You should ensure that:
+- The network has its own firewall settings to prevent people you don't trust from using the network to access your FRAME (including over ports 80 and 443 for various administrative browser apps, and port 9090 for Cockpit).
+- Your FRAME has a secure [password for the `pi` user](../day-1/security/README.md#how-to-change-the-pi-users-password), because it can be used for remotely [accessing the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+
+:::
+
+### temporarily
+
+#### via Cockpit
+
+1. [Open Cockpit](../day-1/sw-access/README.md#cockpit).
+2. If Cockpit's top menubar displays a yellow lock icon with the label "Limited access", click on it to enable administrative access.
+3. Open the "Networking" page using Cockpit's navigation sidebar.
+4. In the "Firewall" section, click on the "Enabled/Disabled" toggle.
+
+#### via the terminal
+
+To disable the firewall until the next boot:
+
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+2. Run the command `sudo systemctl stop firewalld`.
+
+To undo this change:
+
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+2. Run the command `sudo systemctl start firewalld`.
+
+### persistently
+
+#### via Cockpit
+
+1. [Open Cockpit](../day-1/sw-access/README.md#cockpit).
+2. If Cockpit's top menubar displays a yellow lock icon with the label "Limited access", click on it to enable administrative access.
+3. Open the "Services" page using Cockpit's navigation sidebar.
+4. Click on the "firewalld" service entry to open the firewalld service management page.
+5. Click on the "Start and enable/Stop and disable" toggle to change it to the disabled state.
+6. In the menu next to the "Start and enable/Stop and disable" toggle, click on the "Disallow running (mask)" menu item.
+
+#### via the terminal
+
+To disable the firewall on every boot:
+
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+2. Run the command `sudo systemctl disable --now firewalld`.
+3. Run the command `sudo systemctl mask firewalld`.
+
+To undo this change:
+
+1. [Enter the RPi's terminal](../day-1/sw-access/README.md#the-frames-terminal).
+2. Run the command `sudo systemctl enable --now firewalld`.
+3. Run the command `sudo systemctl unmask firewalld`.