x230i作为办公用的笔记本,今天完成了它的使命,正式退役。鉴于曾经的树莓派性能已经不能满足现在需求,x230i开始逐步取代树莓派,成为家中主力服务器的角色。

安装系统

我接触的过的Linux发型版主要有以下几个:

  1. Slackware ,这个发型版是我的入门Linux,通过这个发型版深入地学到了很多系统的本质问题,但是这个系统相对来说比较小众,目前已基本不再接触。

  2. CentOS ,工作中一直用的发型版,以稳定著称,但是个人非常不喜欢这个发型版,很多应用太过老旧,包管理也非常难用,其它还有很多问题,反正用了这么多年一直也没能习惯。

  3. Arch ,系统很简洁,没有任何多余的东西,一切都根据自己的需要来定制,除了更新太频繁外,其它的理念都非常符合我的口胃。作为工作机,更新频繁还是很好的,做为服务器来用,还是有点风险,或者说经常更新还是太麻烦。

  4. Ubuntu ,这大概是当前最流行的发型版了,不过总觉得这个发型版本有点怪,但又是说不了来哪里不舒服。

  5. Manjaro ,这个发型版印象中作为桌面系统还是不错的,师承Arch,作为服务器也同样有更新频繁的问题。

  6. Debian ,这个发型版目前是我最喜欢的一个了,适用平台相当广范,系统组件简洁,占用内存小,更新也不像 Arch 那么频繁,作为服务器来说,我觉得非常不错的选择。

经常这些版本试用比较,我目前倾向于用 Debian 作为主要服务器系统,如果需要作为桌面系统,我的选择可以是 DebainManjaroArch

当前 Debian 的最新版是 Debian 11 bullseye ,那么就以这个版本为来作为我的服务器系统了。

安装过程非常简单,下载 debian-11.0.0-amd64-netinst.iso ,通过 Rufus 制作U盘安装盘,通过U盘启动,安装即可。过程不在详述。

安装包源配置

由于某些原因,在国内,Debian默入的安装包源比较慢,所以装安装完系统后,需要将软件包源替换成国内的镜像源。

  leen@x230i:~$ cat /etc/apt/sources.list
  # deb cdrom:[Debian GNU/Linux 11.0.0 _Bullseye_ - Official amd64 NETINST 20210814-10:07]/ bullseye main

  #deb cdrom:[Debian GNU/Linux 11.0.0 _Bullseye_ - Official amd64 NETINST 20210814-10:07]/ bullseye main

  deb http://mirrors.ustc.edu.cn/debian/ bullseye main
  deb-src http://mirrors.ustc.edu.cn/debian/ bullseye main

  deb http://security.debian.org/debian-security bullseye-security main
  deb-src http://security.debian.org/debian-security bullseye-security main

  # bullseye-updates, to get updates before a point release is made;
  # see https://www.debian.org/doc/manuals/debian-reference/ch02.en.html#_updates_and_backports
  deb http://mirrors.ustc.edu.cn/debian/ bullseye-updates main
  deb-src http://mirrors.ustc.edu.cn/debian/ bullseye-updates main

常用软件安装

  1. apt install sudo

  2. apt install vim

  3. apt install htop

  4. apt install git

  5. apt install tree

  6. apt install samba

  7. apt install tmux

  8. apt install lrzsz

  9. apt install tcpdump

  10. apt install ethtool

  11. apt install build-essential

  12. apt install flex bison

USB磁盘挂载配置

debian系统默情况下没有自动将USB磁盘自动挂载到某个目录的动作。需要自己编写脚本来实现监控。

  1. 首先需要在 /etc/udev/rules.d/ 目录中新增一个文件 11-usb-auto-mount.rules ,内容如下:

    KERNEL=="sd[a-z][0-9]", SUBSYSTEMS=="usb", ACTION=="add", RUN+="/bin/systemctl start usb-mount@%k.service"
    KERNEL=="sd[a-z][0-9]", SUBSYSTEMS=="usb", ACTION=="remove", RUN+="/bin/systemctl stop usb-mount@%k.service"
  2. /etc/systmed/system 目录中新增一个服务文件 usb-mount@.service , 内容如下:

      [Unit]
      Description=Mount USB Drive on %i
    
      [Service]
      Type=oneshot
      RemainAfterExit=true
      ExecStart=/usr/local/bin/usb-mount.sh add %i
      ExecStop=/usr/local/bin/usb-mount.sh remove %i
  3. /usr/local/bin 目录中新增一个脚本文件 usb-mount.sh , 内容如下:

      #!/bin/bash
    
      # This script is called from our systemd unit file to mount or unmount
      # a USB drive.
    
      usage()
      {
          echo "Usage: $0 {add|remove} device_name (e.g. sdb1)"
          exit 1
      }
    
      if [[ $# -ne 2 ]]; then
          usage
      fi
    
      ACTION=$1
      DEVBASE=$2
      DEVICE="/dev/${DEVBASE}"
    
      # See if this drive is already mounted, and if so where
      MOUNT_POINT=$(/bin/mount | /bin/grep ${DEVICE} | /usr/bin/awk '{ print $3 }')
    
      do_mount()
      {
          if [[ -n ${MOUNT_POINT} ]]; then
              echo "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
              exit 1
          fi
    
          # Get info for this drive: $ID_FS_LABEL, $ID_FS_UUID, and $ID_FS_TYPE
          eval $(/sbin/blkid -o udev ${DEVICE})
    
          # Figure out a mount point to use
          LABEL=${ID_FS_LABEL}
          if [[ -z "${LABEL}" ]]; then
              LABEL=${DEVBASE}
          elif /bin/grep -q " /media/${LABEL} " /etc/mtab; then
              # Already in use, make a unique one
              LABEL+="-${DEVBASE}"
          fi
          MOUNT_POINT="/media/${LABEL}"
    
          echo "Mount point: ${MOUNT_POINT}"
    
          /bin/mkdir -p ${MOUNT_POINT}
    
          # Global mount options
          OPTS="rw,relatime"
    
          # File system type specific mount options
          if [[ ${ID_FS_TYPE} == "vfat" ]]; then
              OPTS+=",users,gid=100,umask=000,shortname=mixed,utf8=1,flush"
          fi
    
          if ! /bin/mount -o ${OPTS} ${DEVICE} ${MOUNT_POINT}; then
              echo "Error mounting ${DEVICE} (status = $?)"
              /bin/rmdir ${MOUNT_POINT}
              exit 1
          fi
    
          echo "**** Mounted ${DEVICE} at ${MOUNT_POINT} ****"
      }
    
      do_unmount()
      {
          if [[ -z ${MOUNT_POINT} ]]; then
              echo "Warning: ${DEVICE} is not mounted"
          else
              /bin/umount -l ${DEVICE}
              echo "**** Unmounted ${DEVICE}"
          fi
    
          # Delete all empty dirs in /media that aren't being used as mount
          # points. This is kind of overkill, but if the drive was unmounted
          # prior to removal we no longer know its mount point, and we don't
          # want to leave it orphaned...
          for f in /media/* ; do
              if [[ -n $(/usr/bin/find "$f" -maxdepth 0 -type d -empty) ]]; then
                  if ! /bin/grep -q " $f " /etc/mtab; then
                      echo "**** Removing mount point $f"
                      /bin/rmdir "$f"
                  fi
              fi
          done
      }
    
      case "${ACTION}" in
          add)
              do_mount
              ;;
          remove)
              do_unmount
              ;;
          ,*)
    
              ;;
      esac
  4. udevadm control –reload-rules

  5. systemctl daemon-reload

上面的步骤看起来比繁琐,最初搜索如何挂载USB磁盘的时候,还有一个更简洁的方案(https://www.axllent.org/docs/auto-mounting-usb-storage/):

  1. vim /etc/udev/rules.d/11-media-by-label-auto-mount.rules

      KERNEL!="sd[a-z][0-9]", GOTO="media_by_label_auto_mount_end"  
      # Import FS infos  
      IMPORT{program}="/sbin/blkid -o udev -p %N"  
      # Get a label if present, otherwise specify one  
      ENV{ID_FS_LABEL}!="", ENV{dir_name}="%E{ID_FS_LABEL}"  
      ENV{ID_FS_LABEL}=="", ENV{dir_name}="usbhd-%k"  
      # Global mount options  
      ACTION=="add", ENV{mount_options}="relatime"  
      # Filesystem-specific mount options  
      ACTION=="add", ENV{ID_FS_TYPE}=="vfat|ntfs", ENV{mount_options}="$env{mount_options},utf8,gid=100,umask=002"  
      # Mount the device  
      ACTION=="add", RUN+="/bin/mkdir -p /media/%E{dir_name}", RUN+="/bin/mount -o $env{mount_options} /dev/%k /media/%E{dir_name}"  
      # Clean up after removal  
      ACTION=="remove", ENV{dir_name}!="", RUN+="/bin/umount -l /media/%E{dir_name}", RUN+="/bin/rmdir /media/%E{dir_name}"  
      # Exit  
      LABEL="media_by_label_auto_mount_end"
  2. udevadm control –reload-rules

但是偿试这个方案的时候发现有个问题就是,指定的目录看不到挂载的磁盘内容,同时脚执行过程也没有任何报错,后来才明白这是因为 namespace 导致的问题。虽然可以解决这个问题,也 不建议 直接在 udev rule中直接用mount命令(详见:https://wiki.archlinux.org/title/udev)。

断电延迟关机配置

笔记本有自带电池,可以确保在突然断电后,系统仍然在运行,电力最多也只能支撑两个小时左右。当然断电后继续运行的意义也不大,这个时候应该进行优雅的关机操作,以确保相应的数据都能存入磁盘。如果很短时间的断电,那么就不需要关机了。所以我希望实现一个功能就是在断电后的半个小时内,如果还没有通电那么笔记本就自动关机,如果在半小时内又通电了,就什么都不做。另外因为笔记本设定了通电开机,所以在关机后,如果通电了,那么笔记本会自动开机。

实现延时关机的功能需要以下几个方面的参于:

  1. vim /dev/udev/rules.d/99-delayed-poweroff.rules , 这文件用来感知电源变化

      SUBSYSTEM=="power_supply", ENV{POWER_SUPPLY_ONLINE}=="0", RUN+="/usr/bin/systemctl start delayed-poweroff.timer"
      SUBSYSTEM=="power_supply", ENV{POWER_SUPPLY_ONLINE}=="1", RUN+="/usr/bin/systemctl stop delayed-poweroff.timer"
  2. vim /etc/systemd/system/delayed-poweroff.timer , 这个文件用来配置延时定时器

      [Unit]
      Description=Delayed Poweroff when AC unplugin
    
      [Timer]
      OnActiveSec=30min
    
      [Install]
      WantedBy=timers.target
  3. vim /etc/systemd/system/delayed-poweroff.service , 这个文件用来执行关机命令

      [Unit]
      Description=Delayed poweroff service when AC unplugin
    
      [Service]
      Type=simple
      ExecStart=/usr/sbin/poweroff