mirror of
https://github.com/richb-hanover/OpenWrtScripts.git
synced 2026-03-30 10:44:32 +02:00
Merge 269a2b6cbf into 7c566a78e7
This commit is contained in:
commit
c1f6a5bef1
2 changed files with 281 additions and 40 deletions
144
Why a Spare Router.md
Normal file
144
Why a Spare Router.md
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
# Why a "Spare Router" Configuration?
|
||||
|
||||
Many people who use OpenWrt wind up with unused routers when
|
||||
they retire one for a newer device.
|
||||
These are perfectly functioning devices that are perhaps older
|
||||
or missing a certain function.
|
||||
|
||||
They could be easily re-used and passed along to friends, family or neighbors.
|
||||
BUT... you have to solve a couple problems:
|
||||
|
||||
1. The router retains all your personal info:
|
||||
passwords, certificates, idiosyncratic packages. etc.
|
||||
2. You can't remember how it was configured, so you
|
||||
can't even connect to it.
|
||||
|
||||
**The remedy:** A "spare router" configuration script that
|
||||
you can use when you take a router out of service.
|
||||
It leaves the router with current OpenWrt firmware
|
||||
configured for Wifi access, and
|
||||
a known useful set of package to make it easy to reuse.
|
||||
The script also prints a label that you can attach to
|
||||
the router so that you can get started quickly the next
|
||||
time you get it out.
|
||||
|
||||
## Usage
|
||||
|
||||
When you retire a router from service, run this script.
|
||||
It is available at
|
||||
[config-spare-router.sh](https://github.com/richb-hanover/OpenWrtScripts/blob/master/config-spare-router.sh)
|
||||
To use it:
|
||||
|
||||
* Connect your laptop via Ethernet to a LAN port
|
||||
* Connect the router's WAN Ethernet to the Internet
|
||||
(perhaps the LAN port of the new router).
|
||||
* Use the LuCI GUI to reset settings to
|
||||
factory default (**System -> Backup/Flash firmware**)
|
||||
* Use the [Firmware Selector](https://firmware-selector.openwrt.org/)
|
||||
to find and flash the latest firmware
|
||||
* SSH into the router using the Ethernet connection
|
||||
* Run the attached script (see the instructions within it)
|
||||
* The script prints a label: cut it out and tape it to the router
|
||||
* _Pro tip:_ Printing the label in 12-point type produces a
|
||||
"business card" size label.
|
||||
* _Pro tip:_ Snip the model number from the paper
|
||||
and tape it directly to the power brick.
|
||||
(Use the text from the "Power Brick Label" section.)
|
||||
* _Pro tip:_ Place the router and its power brick in a Ziploc bag
|
||||
to keep them together.
|
||||
|
||||
The `config-spare-router.sh` script may be run multiple times without bad effect.
|
||||
When the script completes, it displays configuration similar to this,
|
||||
suitable for printing and taping to the router.
|
||||
|
||||
```text
|
||||
# ======= Printed with: print-router-label.sh =======
|
||||
# Device: Linksys E8450 (UBI)
|
||||
# OpenWrt: OpenWrt 23.05.5 r24106-10cc5fcd00
|
||||
# Connect to: http://SpareRouter.local
|
||||
# or: ssh root@SpareRouter.local
|
||||
# LAN: 172.30.42.1
|
||||
# User: root
|
||||
# Login PW: SpareRouter
|
||||
# Wifi SSID: SpareRouter
|
||||
# Wifi PW: <no password>
|
||||
# Configured: 2024-11-28
|
||||
# === See github.com/richb-hanover/OpenWrtScripts ===
|
||||
#
|
||||
# Label for Power Brick: Linksys E8450 (UBI)
|
||||
```
|
||||
|
||||
## When you (re)deploy the router
|
||||
|
||||
The default settings are (intentionally) insecure.
|
||||
Remember to change the following:
|
||||
|
||||
* Root password (**System -> Administration**)
|
||||
* Wifi credentials (**Network -> Wireless**)
|
||||
* Enable other Wifi radios (**Network -> Wireless**)
|
||||
* Change the LAN interface IP address and other settings as needed (**Network -> Interfaces**)
|
||||
* (Optional) Configure SQM (**Network -> SQM QoS**)
|
||||
* (Optional) Change the hostname (**System -> System**)
|
||||
* (Optional) Install other packages as needed
|
||||
* (Optional) Travelmate (**Services -> Travelmate**)
|
||||
Click the **Interface Wizard** button one time
|
||||
* (Optional) Re-run the `print-router-label.sh` to create
|
||||
a new label and tape it to the router, so you don't
|
||||
have to fuss the next time you work on it.
|
||||
|
||||
## Rationale for the configuration choices
|
||||
|
||||
This script was designed for ease of use.
|
||||
It presumes that it is being installed on a modern (post-2021)
|
||||
router that has plenty of RAM and Flash storage, so that size
|
||||
was not a consideration.
|
||||
|
||||
* **Root password:** To make it easy to re-use the router,
|
||||
the `root` password is set to `SpareRouter`.
|
||||
There is no need for strong security here, as you will be changing
|
||||
the password when you set it up in its new location.
|
||||
* **LAN Address:** The LAN IP address is set to `172.30.42.1`.
|
||||
This is a
|
||||
[valid private IP address range](https://en.wikipedia.org/wiki/Private_network)
|
||||
(like `10...` and `192.168...` subnets) but it is less commonly used.
|
||||
This means that you can bring the router into virtually any
|
||||
network environment without concern for IP address conflicts,
|
||||
then use the LuCI GUI to configure the LAN.
|
||||
* **Hostname:** is set to "SpareRouter".
|
||||
Because `umdns` is installed, you can connect using
|
||||
`http://SpareRouter.local` or `ssh root@SpareRouter.local`
|
||||
no matter what the LAN IP address is.
|
||||
* **Wifi settings:** The SSID is of the _first_ radio is set
|
||||
to `SpareRouter` without encryption.
|
||||
No other radios are enabled.
|
||||
As with the root password, there is no need for a strong password,
|
||||
because you will be changing it immediately.
|
||||
* **Time Zone:** As a convenience, the time zone is set to `Americas/New York`.
|
||||
You can use the LuCI GUI to re-configure as needed.
|
||||
* **Software packages:** The script installs a minimal set of useful
|
||||
packages that are required to bootstrap a new router.
|
||||
|
||||
* **luci** Released versions of OpenWrt already install `luci`.
|
||||
Re-installing does no harm.
|
||||
* **umdns** Allows the router to advertise its name as "SpareRouter"
|
||||
(e.g., connect using `ssh root@sparerouter.local`)
|
||||
* **luci-app-sqm** All OpenWrt routers ought to have the SQM package
|
||||
installed to minimize bufferbloat. Just do it.
|
||||
* **travelmate** _and_
|
||||
* **luci-app-travelmate** This packages allow a router to
|
||||
act as a Wifi repeater by making a wireless "uplink"
|
||||
to an existing network
|
||||
Even if there's no Ethernet connection for the spare routers's WAN port,
|
||||
you can use the wireless uplink to download additional packages.
|
||||
|
||||
## Modifications
|
||||
|
||||
This script provides a stable platform for re-deploying old routers.
|
||||
Feel free to make suggestions (create an Issue) for _minimal_ tweaks that
|
||||
would improve the script. Enjoy!
|
||||
|
||||
## Old information
|
||||
|
||||
The script also has a large number of lines that are commented out.
|
||||
These were steps for other packages that are not essential for a "Spare Router".
|
||||
Feel free to experiment with these sections in your own copy of the script.
|
||||
177
opkgscript.sh
177
opkgscript.sh
|
|
@ -11,21 +11,27 @@
|
|||
# Thanks, too, to hnyman for important comments on this script
|
||||
#
|
||||
# Version history
|
||||
# 0.2.3 - added support for selective IPK caching with version retention control for offline recovery installs
|
||||
# 0.2.2 - editorial tweaks to help text -richb-hanvover
|
||||
# 0.2.1 - fixed typo in awk script for dependency detection
|
||||
# 0.2.0 - command interface
|
||||
# 0.1.0 - Initial release
|
||||
|
||||
PCKGLIST=/etc/config/opkg.installed # default package list
|
||||
SCRIPTNAME=$(basename $0) # name of this script
|
||||
COMMAND="" # command to execute
|
||||
PCKGLIST=/etc/config/opkg.installed # Default package list
|
||||
IPK_CACHE_LIST="/etc/config/opkg.ipk_cache_list" # List of packages to cache IPKs for
|
||||
IPK_CACHE_DIR="/etc/opkg/ipk_cache" # Directory to store cached IPK files
|
||||
IPK_CACHE_ALL_VERSIONS=false # Cache only the latest IPK per package (default). Set to true to keep all versions.
|
||||
SCRIPTNAME=$(basename $0) # Name of this script
|
||||
COMMAND="" # Command to execute
|
||||
|
||||
INSTLIST=$(mktemp) # list of packages to install
|
||||
PREQLIST=$(mktemp) # list of prerequisite packages
|
||||
INSTLIST=$(mktemp) # List of packages to install
|
||||
PREQLIST=$(mktemp) # List of prerequisite packages
|
||||
|
||||
UPDATE=false # Update the package database
|
||||
OPKGOPT="" # Options for opkg calls
|
||||
VERBOSE=false # Be verbose
|
||||
DEBUG_TRACE=false # Set to true to enable shell debug tracing (set -x)
|
||||
|
||||
UPDATE=false # update the package database
|
||||
OPKGOPT="" # options for opkg calls
|
||||
VERBOSE=false # be verbose
|
||||
|
||||
cleanup () {
|
||||
rm -f $INSTLIST $PREQLIST
|
||||
|
|
@ -40,11 +46,18 @@ Available commands:
|
|||
write write a list of currently installed packages
|
||||
install install packages on list not currently installed
|
||||
script output a script to install missing packages
|
||||
|
||||
cache-ipks download .ipk files for specific packages to a local cache
|
||||
|
||||
Options:
|
||||
-u update the package database
|
||||
-t test only, execute opkg commands with --noaction
|
||||
-v be verbose
|
||||
-x enable shell debug tracing (set -x)
|
||||
|
||||
Configuration:
|
||||
IPK_CACHE_ALL_VERSIONS in script controls whether to cache all .ipk versions or just the latest.
|
||||
Default is to cache only the latest. Set IPK_CACHE_ALL_VERSIONS=true to retain all versions.
|
||||
Warning: caching all versions may consume significant storage and must be cleaned manually.
|
||||
|
||||
$SCRIPTNAME can be used to re-install those packages that were installed
|
||||
before a firmware upgrade but are not part of the new firmware image.
|
||||
|
|
@ -70,35 +83,33 @@ Alternatively, you can execute
|
|||
|
||||
to output a shell script that will contain calls to opkg to install those
|
||||
missing packages. This might be useful if you want to check which packages
|
||||
would be installed of if you want to edit that list.
|
||||
would be installed or if you want to edit that list.
|
||||
|
||||
In order for this script to work after a firmware upgrade or reboot, the
|
||||
opkg database must have been updated. You can use the option -u to do this.
|
||||
|
||||
You can specify the option -t to test what $SCRIPTNAME would do. All calls
|
||||
to opkg will be made with the option --noaction. This does not influence
|
||||
the call to opkg to write the list of installed packages, though.
|
||||
the call to opkg to write the list of installed packages, though.
|
||||
"
|
||||
}
|
||||
|
||||
trap cleanup SIGHUP SIGINT SIGTERM EXIT
|
||||
|
||||
# parse command line options
|
||||
while getopts "htuvw" OPTS; do
|
||||
while getopts "htuvx" OPTS; do
|
||||
case $OPTS in
|
||||
t )
|
||||
OPKGOPT="$OPKGOPT --noaction";;
|
||||
u )
|
||||
UPDATE=true;;
|
||||
v )
|
||||
VERBOSE=true;;
|
||||
[h\?*] )
|
||||
echo_usage
|
||||
exit 0;;
|
||||
t ) OPKGOPT="$OPKGOPT --noaction";;
|
||||
u ) UPDATE=true;;
|
||||
v ) VERBOSE=true;;
|
||||
x ) DEBUG_TRACE=true; VERBOSE=true;;
|
||||
[h\?*] ) echo_usage; exit 0;;
|
||||
esac
|
||||
done
|
||||
shift $(($OPTIND - 1))
|
||||
|
||||
[ "$DEBUG_TRACE" = true ] && set -x
|
||||
|
||||
# Set the command
|
||||
COMMAND=$1
|
||||
|
||||
|
|
@ -110,7 +121,6 @@ fi
|
|||
#
|
||||
# Help
|
||||
#
|
||||
|
||||
if [ "x$COMMAND" == "x" ]; then
|
||||
echo "No command specified."
|
||||
echo ""
|
||||
|
|
@ -125,20 +135,113 @@ fi
|
|||
#
|
||||
# Write
|
||||
#
|
||||
|
||||
if [ $COMMAND = "write" ] ; then
|
||||
if $VERBOSE; then
|
||||
echo "Saving package list to $PCKGLIST"
|
||||
fi
|
||||
if [ $COMMAND = "write" ]; then
|
||||
$VERBOSE && echo "Saving package list to $PCKGLIST"
|
||||
# NOTE: option --noaction not valid for list-installed
|
||||
opkg list-installed > "$PCKGLIST"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#
|
||||
# Cache IPKs
|
||||
#
|
||||
if [ $COMMAND = "cache-ipks" ]; then
|
||||
if [ ! -f "$IPK_CACHE_LIST" ]; then
|
||||
echo "Error: IPK cache list '$IPK_CACHE_LIST' not found."
|
||||
echo "Please create this file and list the packages you want to cache (one per line)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$IPK_CACHE_DIR" ]; then
|
||||
$VERBOSE && echo "Creating IPK cache directory: $IPK_CACHE_DIR"
|
||||
mkdir -p "$IPK_CACHE_DIR" || {
|
||||
echo "Error: Could not create IPK cache directory '$IPK_CACHE_DIR'."
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
$VERBOSE && echo "Caching IPK files from list: $IPK_CACHE_LIST to $IPK_CACHE_DIR"
|
||||
$VERBOSE && echo "Checking freshness of opkg cache..."
|
||||
|
||||
# Only update if lists are older than 5 minutes
|
||||
CACHE_AGE_LIMIT=300 # seconds
|
||||
needs_update=false
|
||||
for list in /var/opkg-lists/*; do
|
||||
if [ ! -f "$list" ] || [ "$(($(date +%s) - $(date -r "$list" +%s)))" -gt "$CACHE_AGE_LIMIT" ]; then
|
||||
needs_update=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if $needs_update; then
|
||||
$VERBOSE && echo "Running opkg update..."
|
||||
opkg update
|
||||
$VERBOSE && echo "Finished opkg update"
|
||||
else
|
||||
echo "Skipping opkg update: cache is fresh"
|
||||
fi
|
||||
|
||||
TOTAL=0
|
||||
DOWNLOADED=0
|
||||
SKIPPED=0
|
||||
REMOVED=0
|
||||
|
||||
while read PACKAGE; do
|
||||
PACKAGE=$(echo "$PACKAGE" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||
[ -z "$PACKAGE" ] && continue
|
||||
TOTAL=$((TOTAL + 1))
|
||||
|
||||
IPK_LATEST_FILENAME=$(opkg info "$PACKAGE" | grep "^Filename:" | awk '{print $2}')
|
||||
[ -z "$IPK_LATEST_FILENAME" ] && {
|
||||
echo "Warning: Could not find filename for package '$PACKAGE'. Skipping."
|
||||
continue
|
||||
}
|
||||
|
||||
BASE_PACKAGE_NAME=$(opkg info "$PACKAGE" | grep "^Package:" | awk '{print $2}')
|
||||
IPK_LATEST_PATH="$IPK_CACHE_DIR/$IPK_LATEST_FILENAME"
|
||||
|
||||
if ! $IPK_CACHE_ALL_VERSIONS && [ -n "$BASE_PACKAGE_NAME" ]; then
|
||||
CACHED_FILES=$(find "$IPK_CACHE_DIR" -maxdepth 1 -type f -name "${BASE_PACKAGE_NAME}_*.ipk")
|
||||
for CACHED_FILE in $CACHED_FILES; do
|
||||
CACHED_FILENAME=$(basename "$CACHED_FILE")
|
||||
if [ "$CACHED_FILENAME" != "$IPK_LATEST_FILENAME" ]; then
|
||||
$VERBOSE && echo "Removing old version of $BASE_PACKAGE_NAME: $CACHED_FILENAME"
|
||||
rm -f "$CACHED_FILE" || echo "Warning: Failed to remove $CACHED_FILE"
|
||||
REMOVED=$((REMOVED + 1))
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -f "$IPK_LATEST_PATH" ]; then
|
||||
echo "$PACKAGE is up to date ($IPK_LATEST_FILENAME)"
|
||||
SKIPPED=$((SKIPPED + 1))
|
||||
else
|
||||
$VERBOSE && echo "Downloading $PACKAGE → $IPK_LATEST_FILENAME"
|
||||
opkg $OPKGOPT download "$PACKAGE"
|
||||
if [ $? -eq 0 ] && [ -f "./$IPK_LATEST_FILENAME" ]; then
|
||||
mv "./$IPK_LATEST_FILENAME" "$IPK_LATEST_PATH" || echo "Error: Failed to move downloaded IPK"
|
||||
$VERBOSE && echo "Moved to $IPK_CACHE_DIR"
|
||||
DOWNLOADED=$((DOWNLOADED + 1))
|
||||
else
|
||||
echo "Warning: Download failed or file missing for '$PACKAGE'"
|
||||
fi
|
||||
fi
|
||||
done < "$IPK_CACHE_LIST"
|
||||
|
||||
echo ""
|
||||
echo "IPK Cache Summary:"
|
||||
printf " %-25s %d\n" "Packages scanned:" $TOTAL
|
||||
printf " %-25s %d\n" "New downloads:" $DOWNLOADED
|
||||
printf " %-25s %d\n" "Older versions removed:" $REMOVED
|
||||
printf " %-25s %d\n" "Already up to date:" $SKIPPED
|
||||
echo ""
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#
|
||||
# Update
|
||||
#
|
||||
|
||||
if $UPDATE; then
|
||||
opkg $OPKGOPT update
|
||||
fi
|
||||
|
|
@ -146,12 +249,9 @@ fi
|
|||
#
|
||||
# Check
|
||||
#
|
||||
|
||||
if [ $COMMAND == "install" ] || [ $COMMAND == "script" ]; then
|
||||
# detect uninstalled packages
|
||||
if $VERBOSE && [ $COMMAND != "script" ]; then
|
||||
echo "Checking packages... "
|
||||
fi
|
||||
$VERBOSE && [ $COMMAND != "script" ] && echo "Checking packages... "
|
||||
cat "$PCKGLIST" | while read PACKAGE SEP VERSION; do
|
||||
# opkg status is much faster than opkg info
|
||||
# it only returns status of installed packages
|
||||
|
|
@ -162,10 +262,10 @@ if [ $COMMAND == "install" ] || [ $COMMAND == "script" ]; then
|
|||
# collect prerequisites
|
||||
opkg info "$PACKAGE" |
|
||||
awk "/^Depends: / {
|
||||
sub(\"Depends: \", \"\"); \
|
||||
gsub(\", \", \"\\n\"); \
|
||||
print >> \"$PREQLIST\"; \
|
||||
}"
|
||||
sub(\"Depends: \", \"\");
|
||||
gsub(\", \", \"\\n\");
|
||||
print >> \"$PREQLIST\";
|
||||
}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
|
@ -173,15 +273,12 @@ fi
|
|||
#
|
||||
# Install or script
|
||||
#
|
||||
|
||||
if [ $COMMAND == "install" ]; then
|
||||
# install packages
|
||||
cat "$INSTLIST" | while read PACKAGE; do
|
||||
if grep -q "^$PACKAGE\$" "$PREQLIST"; then
|
||||
# prerequisite package, will be installed automatically
|
||||
if $VERBOSE; then
|
||||
echo "$PACKAGE installed automatically"
|
||||
fi
|
||||
$VERBOSE && echo "$PACKAGE installed automatically"
|
||||
else
|
||||
# install package
|
||||
opkg $OPKGOPT install $PACKAGE
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue