Your Old Phone Can Host a Website

In the previous guide in this series, we turned a 2015 Xiaomi Redmi 2 into a video download server with postmarketOS. That same phone can go one step further: become a real web server. Not a toy — a server that answers 700+ requests per second, uses about four megabytes of RAM, and draws a few watts of power. I know, because I measured it on the actual phone.

Why would you want this? Maybe you are learning web development and want a machine of your own to test on. Maybe you want to host a personal website or a dashboard for your family, reachable from every device in the house. Maybe you just like the idea of a 10-year-old phone doing useful work instead of sitting in a drawer. All of those are good reasons, and the setup takes about ten minutes once postmarketOS is running.

This guide assumes you already have postmarketOS installed on your phone. If you do not, read the first article in this series first — it walks through flashing postmarketOS from start to finish.

Why a Phone Works as a Web Server

Serving static web pages is one of the lightest jobs a computer can do. There is no video encoding, no database, no heavy math. The server reads a file from disk and sends it over the network. Even a 2015 phone with a four-core Snapdragon 410 barely notices.

Here is what I measured on the real device after everything below was set up. I ran a load test from my computer: 50 parallel connections hammering the phone with 2,000 requests.

Metric Measured on Redmi 2 (2015)
Throughput 740 requests per second
Average response time 65 ms
Slowest 5% of requests 124 ms or faster
Requests failed 0 out of 2,000
CPU usage during the test about 20%
nginx memory footprint 4.3 MB
Idle system RAM still free ~600 MB

To put 740 requests per second in context: a busy personal blog might get a few thousand page views per day, which averages out to less than one request per second. The phone can handle the traffic of a moderately popular website without breaking a sweat. The real bottleneck on this setup is not the CPU or the RAM — it is the phone's 2.4 GHz Wi-Fi, which limits how fast data can move between the phone and the network.

The other advantage is cost. The phone already exists, so the server costs $0. It uses a few watts from its charger, compared to 30–60 watts for a typical desktop PC running 24/7. The battery acts as a tiny uninterruptible power supply during brief outages. You get a silent, always-on web server for free.

What You Need

  • An old Android phone running postmarketOS (see the first article in this series to get there)
  • The phone connected to your home Wi-Fi
  • A way to run commands on the phone: either the terminal app on the touchscreen, or SSH from your computer
  • A modern web browser on any device in your house to test the result

Install nginx

nginx is a web server used by a large share of the internet. It is small, fast, and packaged for Alpine Linux, which postmarketOS is based on. Installing it is one command:

sudo apk add nginx

Unlike the cron daemon in the previous article, nginx ships with its own systemd service unit on current postmarketOS images, so enabling it is straightforward:

sudo systemctl enable --now nginx

The --now flag starts it immediately and enables it to start on every boot. If your postmarketOS image is older and uses OpenRC instead of systemd, use rc-service nginx start and rc-update add nginx instead.

The First Gotcha: the Empty Default Page

Now point a browser at the phone and you will see... a 404 page. This confused me for a while. The server was clearly running, but every request came back "Not Found."

The reason: on Alpine Linux, the default nginx configuration is a placeholder that returns 404 for everything. It exists to prevent accidental exposure of other virtual hosts on the system, not to serve real content. Look at the file and you will see the whole thing:

cat /etc/nginx/http.d/default.conf
# This is a default site configuration which will simply return 404, preventing
# chance access to any other virtualhost.

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # Everything is a 404
    location / {
        return 404;
    }
}

A 404 for everything is exactly what it says on the tin. So step one is to replace this placeholder with a real server block. The website files live in /var/lib/nginx/html, which is the default root directory for nginx on Alpine.

sudo sh -c 'cat > /etc/nginx/http.d/default.conf << "EOF"
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/lib/nginx/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}
EOF'

Then create a test page so there is something to see:

sudo mkdir -p /var/lib/nginx/html
sudo sh -c 'echo "<h1>Hello from my old phone!</h1><p>This page is served by a 2015 phone running postmarketOS.</p>" > /var/lib/nginx/html/index.html'

Check the configuration for syntax errors, then reload nginx:

sudo nginx -t
sudo systemctl reload nginx

nginx -t should report that the configuration test is successful. Test from the phone itself:

curl http://localhost

You should see the HTML of your test page. If you do, the server works — but your computer still cannot reach it. Which brings us to gotcha number two.

The Second Gotcha: the Firewall Blocks Everything

postmarketOS ships with a firewall enabled by default, and its default policy is to drop all incoming connections except SSH, DNS, and a few system services. This is good security, but it means port 80 is silently blocked from the rest of your network. The phone can talk to itself, but nothing else can get in.

You can see this in action: from your computer, ping to the phone works, but a web request just hangs until it times out.

The fix is one small rule file. postmarketOS loads firewall rules from /etc/nftables.d/, with a matching nftables.service systemd unit. Add a file named 50_http.nft to open port 80 on Wi-Fi interfaces:

sudo sh -c 'cat > /etc/nftables.d/50_http.nft << "EOF"
table inet filter {
    chain input {
        iifname "wlan*" tcp dport 80 accept comment "accept HTTP on wlan"
    }
}
EOF'

Then restart the firewall so the rule takes effect:

sudo systemctl restart nftables

Now test from your computer. Find the phone's IP address on the phone with ip a (look for wlan0, which is your Wi-Fi connection), then open a browser on any device in the house and visit http://192.168.1.50 (use your phone's actual IP). You should see "Hello from my old phone!"

If it still does not work, the most common cause is a router setting called client isolation or AP isolation, which prevents devices on the same network from talking to each other. Check your router's settings page and disable it for this network.

What It Can (and Can't) Do

With a working web server, here is what this phone can realistically do:

  • Host a personal website for your family or a portfolio page. Static sites are this phone's home turf.
  • Serve a LAN dashboard — weather, calendar, a shared link collection. Anything that is just HTML, CSS, and a little JavaScript.
  • Be a test server for learning web development, safe from the public internet.
  • Share files over the browser with a small HTML page listing downloads.
  • Grow into more: install PHP and SQLite (sudo apk add php82-fpm) for dynamic pages, or put an SSH reverse tunnel in front of it so you can reach it from outside your home (search this site's Tailscale guide for the safe way).

What it cannot do: heavy dynamic sites with big databases, video streaming with on-the-fly transcoding, or handling thousands of concurrent visitors. That is not what this is for. This is a small, quiet, always-on server for personal projects.

Two honest notes. First, the battery: keeping any phone plugged in 24/7 ages the battery. Remove the battery and power it with a 5V USB cable directly if you can, or keep an eye on it. Second, the phone's 2.4 GHz Wi-Fi is the speed ceiling — fine for serving pages, not for copying large files around the house.

FAQ

Do I need to know Linux to do this?

You need to copy-paste commands, and it helps to understand what cd and sudo do. The postmarketOS installation in the first article of this series is the harder half; this part is ten minutes of commands.

Is a 2015 phone really fast enough?

Measured on a real Redmi 2: 740 requests per second, zero failures, 65 ms average response. For a personal website that is more than enough, with room to spare.

Why not just use a Raspberry Pi?

If you already own one, use it — this guide is about the phone you already have. The phone wins on cost (free) and power draw (a few watts), and loses on connectivity options and having no GPIO pins. For serving web pages, the differences do not matter.

Can people on the internet visit my phone's website?

Not directly — the phone sits behind your home router, and opening ports to the internet is risky. Use a safe remote access tool such as Tailscale instead, which this site covers in another guide.

Will this break my video download server setup?

No. nginx is a separate service with its own configuration, and it does not touch the download queue, cron, or yt-dlp from the previous article. They share the phone happily — the whole system was using under 1 GB of RAM with both running.

What if my router has client isolation on?

Find the setting in your router's admin page — it is sometimes called AP isolation or guest network isolation. Turn it off for your main network, and devices will be able to reach the phone again.

Next Steps

  • Old Android Phone as a Video Download Server — how to install postmarketOS in the first place
  • 10 Things to Do with a Home Server — more ideas for your always-on box
  • Turn an Old PC into a Home Server — the bigger sibling
  • Home Server Maintenance and Monitoring — keep it healthy
  • Use Tailscale for Safe Remote Access — reach your phone's website from anywhere All code in this article was tested and runs successfully on a real Xiaomi Redmi 2 (model 2014813, 2GB RAM) running postmarketOS v25.12 with kernel 6.12.1 — verified August 2026. The full chain was executed on the physical device: package installation (apk add nginx), service enablement (systemctl enable --now nginx), replacing the Alpine placeholder configuration with a real server block, writing the test page, the nftables firewall rule in /etc/nftables.d/50_http.nft with firewall restart, and end-to-end access from a second computer over Wi-Fi (HTTP 200). Performance figures were measured with a 50-concurrent-connection load test of 2,000 requests: 740 requests/second, 65 ms average latency, zero failures.