Tag: Tailscale

  • How I Turned a 2011 MacBook Air into a Headless Ubuntu Server

    How I Turned a 2011 MacBook Air into a Headless Ubuntu Server

     

    How I Turned a 2011 MacBook Air into a Headless Ubuntu Server

    An old laptop does not always need to become electronic waste.Sometimes it just needs a different job.I had a 2011 MacBook Air that was no longer practical as an everyday computer. Modern websites felt heavy, the hardware had limited upgrade options, and using it as a normal desktop no longer made much sense.But the machine still worked.

    The display worked. The SSD worked. The battery still provided some backup power. It was compact, quiet, and already sitting in my home.

    Instead of replacing it, I decided to convert it into a lightweight Linux node for my homelab.

    The final result was a headless Ubuntu Server appliance that I could manage through SSH, Cockpit, and Tailscale. Getting there was not a clean, one-command installation. I ran into networking problems, a USB Ethernet interface that appeared unmanaged, obsolete Wi-Fi configuration, and a laptop that wanted to suspend whenever I closed the lid.

    This article documents the real process: the decisions, mistakes, troubleshooting, and lessons that turned an aging MacBook Air into useful homelab infrastructure.


    Why I Reused the MacBook Air

    Homelab content can make it seem as though you need a rack, enterprise servers, expensive network equipment, and a dedicated room before you can begin.

    That was not realistic for me.

    I live in an apartment, share the space with my family, and build my homelab gradually around a full-time job. Every new device has to justify its cost, power usage, noise, and physical footprint.

    The MacBook Air already solved several of those problems:

    • It was already paid for.
    • It was compact.
    • It consumed relatively little power.
    • It ran quietly.
    • It included a screen and keyboard for initial setup.
    • Its battery could provide limited protection during a brief power interruption.

    My goal was not to turn it into a powerful virtualization server. I already had more capable machines for larger workloads.

    The goal was to create a small Linux appliance that could support lightweight services, testing, monitoring, automation, or other infrastructure tasks.

    That distinction mattered. The project became successful because I selected a role that matched the hardware instead of forcing the hardware to imitate a modern server.

    Hardware Overview and Limitations

    My 2011 MacBook Air before becoming a  dedicated Linux server.

    The machine was an 11-inch 2011 MacBook Air with approximately:

    • 4 GB of RAM
    • A 120 GB internal SSD
    • An older Intel mobile processor
    • USB connectivity
    • Built-in Wi-Fi
    • No standard Ethernet port

    Those specifications are limited by modern standards.

    The memory is not suitable for running many virtual machines. The SSD does not provide large-scale storage. The processor is not appropriate for AI workloads, heavy media transcoding, or a large container stack.

    The absence of a built-in Ethernet port was also important. A server should ideally have a predictable wired network connection, so I needed a USB Ethernet adapter.

    What this hardware could still do well

    The MacBook was still capable of handling:

    • Linux administration practice
    • SSH access
    • Network tools
    • Monitoring agents
    • Lightweight Docker containers
    • Small automation jobs
    • DNS or utility services
    • Backup coordination
    • Test deployments
    • Secure remote administration

    Why I Chose Ubuntu Server 24.04

    I initially considered whether the machine needed a desktop environment.

    It did not.

    A graphical desktop would consume memory and CPU resources without adding much value to a device intended to sit closed and operate remotely.

    I chose Ubuntu Server 24.04 because it offered:

    • Long-term support
    • Strong community documentation
    • Broad hardware compatibility
    • Familiar package management
    • Good support for SSH, Netplan, Cockpit, Docker, and Tailscale
    • Lower resource usage than a full desktop installation

    Ubuntu Server also gave me a better learning opportunity. Instead of depending on graphical settings menus, I would need to understand the network configuration, system services, logs, and remote administration tools directly.

    The installation itself was fairly straightforward. I created a bootable installer, started the MacBook from USB, and installed Ubuntu Server onto the internal SSD.

    After installation, the system booted successfully.

    Then the networking problems started.

     


    The Initial Networking Problem

    The MacBook Air did not have a built-in RJ45 Ethernet port, so I connected a USB Ethernet adapter.

    Linux detected the adapter, but the behaviour was confusing.

    The interface appeared in the system, yet it was not being configured in the way I expected. At one point it showed as unmanaged. The machine either had no usable address or did not retain the correct network setup after changes.

    Coming from desktop Linux, I initially expected NetworkManager to control the connection.

    That assumption was wrong.

    Ubuntu Server commonly uses Netplan as its configuration layer and systemd-networkd as the service that manages the actual interfaces. NetworkManager is more common on desktop installations, but it was not the component responsible for this server’s Ethernet connection.

    Understanding that distinction was the turning point.


    Checking Whether Linux Detected the USB Ethernet Adapter

    Ubuntu successfully detected the USB Ethernet adapter after boot.

    Before editing configuration files, I needed to establish whether this was a hardware problem or a configuration problem.

    I used commands such as:

    ip link

    and:

    ip address

    These commands list the network interfaces recognized by Linux.

    A typical output may contain interfaces such as:

    lo
    enxAABBCCDDEEFF

    The lo interface is the local loopback interface. The second interface could be the USB Ethernet adapter.

    USB network interfaces are sometimes named using a pattern based on their hardware address. In documentation, I recommend replacing the real name with a placeholder such as:

    enxAAABBBCCCDDD

    I also checked the USB devices:

    lsusb

    This helped confirm that Linux could see the physical adapter.

    I then examined the system’s network state:

    networkctl status

    and, for the specific example interface:

    networkctl status enxAAABBBCCCDDD

    The important questions were:

    Does the USB device appear?

    Does Linux create a network interface for it?

    Is the interface up or down?

    Does it have an IP address?

    Which service is expected to manage it?

    Because the adapter appeared in lsusb and ip link, the hardware and driver were functioning. The problem was the network configuration.


    Understanding Netplan

    Netplan is a configuration system used by Ubuntu.

    It reads YAML files from:

    /etc/netplan/

    Netplan does not directly handle every network packet. Instead, it generates configuration for a renderer such as:

    • systemd-networkd
    • NetworkManager

    On Ubuntu Server, the renderer is commonly systemd-networkd.

    A simplified relationship looks like this:

    Netplan YAML
        ↓
    systemd-networkd
        ↓
    Ethernet interface
        ↓
    Local network and internet

    This explained why NetworkManager commands were not solving the problem. NetworkManager was not responsible for the interface.

    To see which Netplan files existed, I used:

    ls -la /etc/netplan/

    I then inspected the configuration:

    sudo cat /etc/netplan/example-config.yaml

    The actual filename can vary. It might be generated by the installer or cloud-init.


    The Obsolete Wi-Fi Configuration

    The existing Netplan configuration focused on Wi-Fi.

    That no longer matched the intended design.

    I wanted the MacBook to operate as a stationary server with a wired connection. Keeping an unused Wi-Fi configuration introduced unnecessary complexity and made it harder to understand which interface should be active.

    My first attempt to disable the old Wi-Fi file was not perfect. I tried moving or renaming it, but the command failed because the target path or filename was not correct.

    Instead of continuing to fight with the move operation, I simplified the active configuration and retained only the Ethernet section.

    This was a useful lesson: configuration cleanup should be deliberate, but the goal is not to preserve every historical setting. The goal is to leave the system in a clear, supportable state.

    Before changing Netplan files, create a backup:

    sudo cp /etc/netplan/example-config.yaml \
      /etc/netplan/example-config.yaml.backup

    Do not store backup files with a .yaml extension inside /etc/netplan/, because Netplan may try to read them. A .backup suffix is safer.


    Creating a Persistent Ethernet Connection

    The first objective was simply to make the wired interface work consistently.

    A DHCP-based Netplan configuration could look like this:

    network:
      version: 2
      renderer: networkd
    
      ethernets:
        enxAAABBBCCCDDD:
          dhcp4: true
          optional: true

    Replace enxAAABBBCCCDDD with the actual interface name shown by:

    ip link

    The optional: true setting prevents boot from waiting indefinitely if the Ethernet adapter is temporarily disconnected.

    YAML formatting is sensitive to indentation. Use spaces, not tabs.

    After editing the file, I validated it:

    sudo netplan generate

    If no errors appeared, I tested the configuration:

    sudo netplan try

    netplan try is safer than immediately applying changes during a remote session because it can automatically roll back if the configuration is not confirmed.

    Once I knew the configuration was correct, I applied it:

    sudo netplan apply

    I then checked the interface:

    ip address show enxAAABBBCCCDDD

    and tested the route:

    ip route

    Finally, I tested connectivity in stages:

    ping -c 4 192.168.x.1
    ping -c 4 1.1.1.1
    ping -c 4 example.com

    These tests answer different questions:

    • Can the server reach the router?
    • Can it reach the internet by IP address?
    • Can DNS resolve a hostname?

    This method is much more useful than running only one ping and guessing at the result.


    Network

    Assigning a Static IP Through Netplan

    DHCP was enough to prove the interface worked, but a server benefits from having a predictable local address.

    SSH, Cockpit, monitoring, and other services are easier to manage when the address does not change.

    There are two common ways to accomplish this:

    Create a DHCP reservation on the router.

    Configure a static address directly on the server.

    For this project, I configured the address through Netplan.

    A sanitized example looks like this:

    network:
      version: 2
      renderer: networkd
    
      ethernets:
        enxAAABBBCCCDDD:
          dhcp4: false
          optional: true
          addresses:
            - 192.168.x.x/24
          routes:
            - to: default
              via: 192.168.x.1
          nameservers:
            addresses:
              - 192.168.x.1
              - 1.1.1.1

    The placeholders represent:

    • 192.168.x.x/24: the server’s static address and subnet
    • 192.168.x.1: the local gateway or router
    • 1.1.1.1: an optional public DNS resolver

    The chosen address must be valid for the local subnet and should not conflict with another device.

    After saving the file, I ran:

    sudo netplan generate

    Then:

    sudo netplan try

    And finally:

    sudo netplan apply

    I confirmed the result with:

    ip address
    ip route
    resolvectl status

    At this stage, the USB Ethernet connection survived reboots and the MacBook had a predictable address.

    This was the point where it started behaving like a real server.


    Installing Cockpit

    Cockpit provides a simple web interface for monitoring and managing the server.

    The command line is essential for Linux administration, but not every task needs to be performed through a terminal.

    I installed Cockpit to provide a lightweight web-based management interface.

    Cockpit can display:

    • CPU usage
    • Memory usage
    • Storage information
    • System logs
    • Running services
    • Network status
    • Software updates
    • Terminal access

    Installation on Ubuntu Server is straightforward:

    sudo apt update
    sudo apt install cockpit

    I enabled the Cockpit socket:

    sudo systemctl enable --now cockpit.socket

    I verified its status:

    systemctl status cockpit.socket

    Cockpit normally listens on port 9090. A sanitized local URL would look like:

    https://192.168.x.x:9090

    A browser may display a certificate warning because Cockpit uses a locally generated certificate by default. On a trusted private network, this can be expected, but users should still confirm they are connecting to the correct device.

    Cockpit became a useful middle ground. It did not replace SSH, but it made routine checks faster and more approachable.


    Installing Tailscale for Secure Remote Access

    Tailscale allows secure remote access without exposing SSH directly to the internet.

    Local access was working, but I also wanted a secure way to reach the server when I was away from home.

    Opening SSH or Cockpit directly to the public internet would have added unnecessary risk.

    I chose Tailscale.

    Tailscale creates an encrypted private network between approved devices. It uses WireGuard underneath but removes much of the manual VPN configuration.

    The general installation process is:

    curl -fsSL https://tailscale.com/install.sh | sh

    Then:

    sudo tailscale up

    The command may provide an authentication URL. That URL is sensitive and should never appear in screenshots, articles, videos, or public documentation.

    After authentication, I checked the connection:

    tailscale status

    I could then reach the MacBook through its Tailscale address or approved device name without exposing its management ports publicly.

    For published documentation, use placeholders such as:

    100.x.x.x
    example-host

    Do not publish the actual Tailscale address, login URL, device inventory, or account details.


    Configuring SSH

    SSH became the primary way I administered the server.

    I installed the OpenSSH server package:

    sudo apt update
    sudo apt install openssh-server

    Then enabled and started the service:

    sudo systemctl enable --now ssh

    I verified it:

    systemctl status ssh

    From another computer, a sanitized connection command would look like:

    ssh [email protected]

    Or through Tailscale:

    ssh [email protected]

    Once basic access was confirmed, a stronger configuration would use SSH keys instead of relying only on a password.

    On the client computer:

    ssh-keygen -t ed25519

    Then copy the public key:

    ssh-copy-id [email protected]

    Before disabling password authentication, always confirm that key-based login works in a separate session. Locking yourself out of a headless server is easy if SSH security settings are changed too quickly.

    A production-minded SSH hardening process may include:

    • Using SSH keys
    • Disabling direct root login
    • Restricting allowed users
    • Keeping the system updated
    • Limiting access through the firewall
    • Using Tailscale instead of exposing port 22 publicly

    Preventing Suspend When Closing the Lid

    The next problem was caused by the MacBook behaving exactly like a laptop.

    When I closed the lid, the system wanted to suspend.

    That is useful for a portable computer. It is unacceptable for a server.

    A server must continue running even when its display is closed.

    On systems using systemd-logind, lid behaviour can be changed in:

    /etc/systemd/logind.conf

    I opened the file:

    sudo nano /etc/systemd/logind.conf

    I configured the relevant options:

    HandleLidSwitch=ignore
    HandleLidSwitchExternalPower=ignore
    HandleLidSwitchDocked=ignore

    After saving the file, I restarted the service:

    sudo systemctl restart systemd-logind

    Because restarting systemd-logind can affect sessions, this should be done carefully. Rebooting the machine is another clean way to ensure the settings take effect:

    sudo reboot

    After the system returned, I closed the lid and tested connectivity from another device.

    SSH remained available.

    Cockpit remained available.

    The wired connection remained active.

    That confirmed the laptop could operate while closed.

    Turning the MacBook into a Headless Linux Appliance

    After disabling suspend-on-lid-close, the MacBook now runs continuously as a headless Linux appliance.

    A headless server is a system that operates without a permanently attached monitor, keyboard, or mouse.

    At the beginning of the project, the MacBook still felt like an old laptop.

    By the end, it had become infrastructure.

    The operating model was now:

    MacBook Air
    ├── Ubuntu Server 24.04
    ├── USB Ethernet
    ├── Static local address
    ├── SSH
    ├── Cockpit
    ├── Tailscale
    └── Lid closed

    Daily administration no longer required touching the physical machine.

    I could:

    • Connect through SSH for command-line work
    • Use Cockpit for quick health checks
    • Use Tailscale for secure remote access
    • Leave the device closed and running quietly

    The built-in keyboard and display were still useful for emergency recovery, but they were no longer part of normal operation.

    This is one of the major benefits of repurposing a laptop. It can function as a compact headless appliance while retaining a built-in emergency console.


    Its Final Role in My Homelab

    The MacBook Air was not intended to replace my primary Proxmox or Docker systems.

    Its role was to complement them.

    A lightweight node like this can be useful for:

    • Monitoring services
    • Uptime checks
    • Network utilities
    • Lightweight automation
    • Small Docker workloads
    • Backup coordination
    • Documentation services
    • Test deployments
    • Tailscale access
    • Secondary management tools

    The exact role can evolve over time.

    The key is to avoid overloading it. With limited memory and an older processor, service selection matters.

    Before deploying a new application, I now ask:

    Is the application lightweight?

    Is it critical?

    Does it need strong storage performance?

    What happens if this old hardware fails?

    Is the workload better suited to another node?

    This keeps the MacBook useful without turning it into a fragile single point of failure.


    Mistakes I Made

    This project worked, but not because every step was correct the first time.

    I assumed NetworkManager controlled the interface

    That assumption came from desktop Linux experience.

    Ubuntu Server was using Netplan with systemd-networkd, so NetworkManager was not the correct place to fix the connection.

    I focused too broadly on “the network”

    The problem became easier once I separated it into:

    • USB detection
    • Interface creation
    • Interface management
    • IP assignment
    • Routing
    • DNS
    • External connectivity

    I retained irrelevant Wi-Fi configuration

    Unused settings made the configuration harder to understand.

    Removing the obsolete wireless section created a cleaner and more predictable setup.

    I attempted to move a configuration file incorrectly

    The command failed because the filename or destination did not match what actually existed.

    The lesson was simple: list and inspect files before changing them.

    ls -la /etc/netplan/

    I had to account for laptop power behaviour

    Installing a server operating system did not automatically make the hardware behave like a server. The lid-close action still needed to be changed.


    Lessons Learned

    Old hardware can still be operationally valuable

    The MacBook could no longer provide a good modern desktop experience, but it was still capable of running a lightweight Linux server.

    Usefulness depends on the workload, not the age printed on the device.

    Linux networking becomes manageable when you understand the layers

    Netplan initially felt confusing because I did not understand which service was responsible for the interface.

    Once I understood the relationship between Netplan and systemd-networkd, the configuration became logical.

    Wired networking is worth the effort for a server

    Wi-Fi can work, but a persistent Ethernet connection generally provides better predictability for stationary infrastructure.

    Static addressing simplifies administration

    A known address makes SSH, Cockpit, monitoring, and troubleshooting easier.

    Remote access should be designed securely

    Tailscale allowed remote management without publishing SSH or Cockpit directly to the internet.

    Headless systems still need a recovery plan

    The MacBook retained a built-in screen and keyboard, which could be useful if networking failed. For other headless machines, a recovery monitor, serial console, or documented rescue process may be necessary.

    Documentation turns troubleshooting into an asset

    Without notes, this project would have been a collection of commands and forgotten mistakes.

    With documentation, it became:

    • A repeatable build
    • A troubleshooting reference
    • A blog article
    • A possible video
    • Evidence of practical Linux experience

      Advice for Reusing an Old Laptop as a Server

      Start by evaluating the machine honestly.

      Check:

      • Processor architecture
      • Available memory
      • Storage health
      • Battery condition
      • Cooling
      • Ethernet options
      • BIOS or firmware behaviour
      • Linux hardware compatibility

      Then choose a modest role.

      Good starter projects include:

      • Uptime Kuma
      • Pi-hole or AdGuard Home
      • Tailscale node
      • Lightweight web server
      • Backup target
      • Samba file share
      • Docker test host
      • Network monitoring
      • Home automation utility node

      Avoid placing irreplaceable data on old hardware without backups.

      Do not make it the only copy of family photos, important documents, or business data.

      Also monitor heat and battery condition. An aging or swollen battery should be handled safely and replaced or removed by someone qualified to service the device.

      Most importantly, do not install ten services on the first day.

      Start with one useful role, document it, monitor the machine, and expand only when the system proves stable.


      Final Reflection

      Repurposing this 2011 MacBook Air was a better investment than buying another new device.

      The hardware cost was effectively zero. The real return came from what I learned:

      • How Ubuntu Server handles networking
      • How Netplan generates network configuration
      • Why NetworkManager was not managing the interface
      • How to troubleshoot a USB Ethernet adapter
      • How to configure persistent wired networking
      • How to assign a static address
      • How to administer Linux with Cockpit
      • How to use Tailscale for secure access
      • How to configure SSH
      • How to convert laptop power behaviour into server behaviour
      • How to operate a system headlessly

      A new mini PC might have been faster and easier.

      It would not necessarily have taught me as much.

      Old hardware forces you to understand constraints. It pushes you to troubleshoot. It makes you think carefully about workload placement, reliability, and system design.

      That is why repurposing old hardware is often a better first investment than buying new equipment.

      The best beginner homelab server is not always the newest machine.

      Sometimes it is the computer already sitting unused in your home, waiting for a better job.