STFN

How I built an off-grid, solar powered webserver and exposed it to the Internet

20 minutes

Here is my newest project: a webpage running on an off-grid server powered solely by solar panels.

​solar.stfn.pl

The Background

I am in the middle of building my house. I mean, I am not building it personally, the construction workers, plumbers, electricians are doing it. The house is in the middle of a piece of land my wife and I bought in 2022. Next to the house there is a shed which we have been using to store gardening equipment and other random stuff. It also served me as a shelter during the cold nights when doing astrophotography and star gazing. While the house will eventually have electricity from the grid, the shed will be kept off-grid.

As the construction is moving on, the people building the house convinced me to buy a cctv camera, so that I can monitor the site and at least its presence will deter any bad guys. I ordered a DTV solar powered security camera with a SIM slot to stream video over LTE. Or so I thought.

When it arrived, I realized I made a mistake, I ordered a wrong one, the one that I ordered was a WiFi one, not LTE, so it would need a separate source of Internet to share its feed.

What I could have done was return it and get the proper one, but I do not like the hassle and awkwardness of returning things, and most of all, I decided this is the perfect moment to do what I have been wanting to do for a long time: Build an off-grid PV system for the shed that could power a separate LTE router and share WiFi for the camera, as well as for people visiting the site, maybe even allow to occasionally work from there. And so the project started.

The PV system

I already have some experience with building 12V powerbanks (blog post: A DIY off-grid 12V powerbank), I “just” needed to add the PV part to charge it.

The solar panel

At first I was thinking of buying a small 30-50 Wp solar panel. But as I was browsing the local marketplace sites, I found a person who was selling lightly used PV panels, as he was replacing them with more powerful ones. The panel barely fit in my VW Polo, I had to drive very carefully because its side was right next to my head, but I managed to transport it to my site, and now I was the proud owner of a 330 Wp PV panel for which I paid only 100PLN (~25EUR). The main issue was securing it to the roof of my shed, but after pondering, I decided it’s heavy enough to just put it on the roof as is. I bolted a metal bar I had from an old project to the back of the panel to make it even heavier and harder to overturn. My shed is low enough to allow me to just push the panel onto the roof with the help of a small step ladder. The metal bar is mounted on the top of the panel so that it goes over the rooftop, so the panel cannot slide down. It also makes space on the sides for the cables.

The panel with the metal bar.

The panel is raised a bit so that the cables can go under its side

Cables and connectors

For the cables connecting the panel to the rest of the system I went with dedicated solar panel cables. Those are thick cables in very hard coating that is resistant to weather and UV rays. The panel itself has short cables going from its underside, terminated with standard PV MC4 connectors. I terminated my cables on one side with the corresponding MC4 connectors, and drove them through the wall of the shed.

Cables going through the side of the shed. They do not have connectors at the second end, so I could just drill holes the size of the cables.

The PV controller

I chose a typical cheap PV controller, that proudly boasts that it can handle 20A, but I would not trust it with half of that value. The controller has three sets of screw connectors, one for the PV panels, second one for the batteries and the third for the output. It’s main goal is to protect the batteries from both overcharging and overdischarging, if the battery voltage falls below the predefined value, around 11V, it will turn off any devices connected to it. There are hundred of models of such controllers available, I just went with a cheap, simple one, this project does not require anything special. Big Clive made a few interesting videos about solar controllers, and I highly recommend watching them before buying one.

Big Clive: Exploring a Mass Produced Solar Charge Controller
Big Clive: 10A vs 100A Solar Charge Controllers

The USB charger and cables

One of the features I wanted to have from the solar installation is being able to at least charge my phone from a USB socket. It took me quite a while to find the USB charger in line with what I needed. I finally found one in the area of car accessories. And that makes sense, cars have internal 12V electrical installation and people in them want to charge their phones. The one I bought fits into the place of a cigarette lighter / 12V output and provides two USB-A ports. The maximum it can output on a single port is 2.4A, which is enough even for a Pi 4b, but only if it runs without power hungry accessories. For a Zero it is way more than enough. The installation was simple, in my set of hole saws I had one with exactly the right diameter, I drilled a hole in the tool box, put it the charger and secured it with a provided ring.

I connected the batteries with the controller using a thick 12 AWG cable with a 20A fuse. The output side I did with a thinner, 18 AWG cable, as I do not expect high loads. I used WAGO connectors to create a parallel connection between every power output, the USB charger, the XT60 sockets, and the cable for the LTE modem.

The toolbox working as a place to store all of the power components. On top of it there is also a 220V voltage converter powered from the batteries. On the desk there is the webserver Pi, and an IKEA lamp converted to use 12V DC.

The inside of the tool box with the batteries, the controller, and all those cables.

Zoom on the internals of the tool box

Side of the box with the external connectors visible. The blueish cable is the micro-USB powering the Pi.

The 220V power converter

A part of the power system that is not being used in the solar webserver project is the 12V to 220V power converter. I think it is nonetheless important to mention it so that you can omit the mistake that I did. I first connected it to the PV controller, as you can see in the attached photos. But it quickly turned out that often on startup it would overload the controller and make it to reset. I’m guessing the converter charges some capacitors on startup and draws a very high current, killing the PV controller. What I did is connect it directly to the batteries. It has its own overdischarge protection, so it will not harm the batteries if used for too long. And now I have a source of standard 220V power to, for example, charge a laptop or a cordless drill battery.

Internet gateway

The gateway to the Internet for the Pi is a Mikrotik LTE AP outdoor router that I also managed to buy second-hand. I mounted it outside the shed and put a standard barrel jack cable through the wall to power it from the PV controller. The router creates a Wi-Fi network for the Pi to connect to, and has an LTE modem to talk to the Internet. I have a limited data quota on my deal, so I am monitoring the traffic usage on the mobile company user portal. So far the webserver has been only using a few megabytes per day of traffic. There is no special configuration on the Mikrotik, just typical 2.4 Ghz Wi-Fi.

The Mikrotik router/modem fastened to the wall of the shed.

And with that, the initial Wi-Fi part of the installation was done. The camera has been working without issues, I can check what is happening at the site using my phone. Sadly, only by using a proprietary app from the vendor. But this is just a temporary solution, once the house is built I plan to move to standard IP cameras and record the feeds using open source software like Frigate.

Moving Further: Making a webserver

With the Wi-Fi done, I started thinking about other possible uses for the installation that I built. And I thought that it would be awesome to use it to make a solar powered webserver and host my own, personal website. And so I went this route.

The choice of hardware was simple, a Raspberry Pi Zero W in my drawer of Pis, waiting for better times was the obvious choice. I added to it a BMP280 pressure/humidity/temperature sensor to gather some environmental data. The USB charger I mentioned before became the power source for the Pi. Exposing the Pi to the Internet had been an issue until I learned I can go over (CG)NATs using Wireguard. And with all of the components in place, off I went.

The Server

The hardware is just a Pi Zero W in the official Pi case, absolutely nothing interesting to talk about here.

For the server software, I went away from my typical Nginx setup and chose Lighttpd, because it is, well, light. The website is static HTML (well, not exactly static, but from the perspective of the webserver it is, more on that later), so configuring the server was only a matter of cloning the git repo to /var/wwww/html and modifying the config file:

Below are only the lines I added or modified. I added the mod_accesslog server module to monitor traffic, and configured the file that stores the access log. I also changed the server port to 81, as this server does not handle traffic directly, but is downstream of a reverse proxy that actually serves content on port 80.

/etc/lighttpd/lighttpd.conf

server.modules = (
        "mod_indexfile",
        "mod_access",
        "mod_alias",
        "mod_redirect",
        "mod_accesslog",
)

server.port                 = 81
accesslog.filename = "/var/log/lighttpd/access.log"

Exposing the website to the Internet

Finding a good way to expose a locally hosted webserver to the Internet has been a big problem for me for a long time. The breakthrough came when I learned that I can use Wireguard VPN to punch through NATs. This method requires to also have another server, that is publicly accessible to be a proxy between the local server and the wider Internet.

This of course raises a question, is this website actually solar powered when making it work requires another server in a datacenter? One could say no, but I think that well, packets flowing through the Internet pass a lot of different servers either way, then there are the mobile signal towers, the DNS servers and all the other components that run to make the Internet work. So having a VPS on a machine in a datacenter that is running either way does not make a difference.

For the public server, I am using a Hetzner’s VPS which I have been already using for different tasks. It does not have to be powerful for being a proxy, all it does is run a webserver that passes the traffic between the Pi and the Internet. The VPS also handles the TLS certificates for the HTTPS to work. The TLS certificates are configured using Certbot, which makes obtaining and configuring them very easy, basically a single command. The domain also points to that public server.

The Pi and the VPS are connected using Wireguard. I already described how to do a typical point-to-point Wireguard connection in my blog post about PiHole, you can consult it for reference:

WireGuard and PiHole for secure ad blocking on your smartphone

However, I want to show you the Wireguard config file on the Pi, because it has one important part:

[Interface]
Address = 10.8.0.3/24
PrivateKey = <Pi private WG key>

[Peer]
PublicKey = <server public WG key>
AllowedIPs = 10.8.0.0/24
Endpoint = <server public IP address>:51820
PersistentKeepalive = 10

The crucial part is the PersistentKeepalive stanza in the config, which ensures that the connection is being kept up all the time, and so the server can continuously communicate with the NATed Pi.

On the public server I am running Nginx, because I am used to it. Here’s how it is configured:

/etc/nginx/sites-available/solar

server {
    server_name solar.stfn.pl;

    location / {
        proxy_pass http://10.8.0.3:81;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/solar.stfn.pl/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/solar.stfn.pl/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {
    if ($host = solar.stfn.pl) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80;
    server_name solar.stfn.pl;
    return 404; # managed by Certbot

Most of the lines here are automatically added by Certbot, and so are not interesting for us. The most important part is the location dictionary. Here it is defined that Nginx works as a reverse proxy, passing requests from the clients to 10.8.0.3 which is the Pi’s Wireguard IP address. Nginx contacts the Pi on port 81, because it itself is listening on port 80 for traffic incoming from the wider Internet. Remember that port 81 needs to be opened in the VPS’s firewall.

Pyriodic Backend

At the top of the webpage there is a green box showing the current climate data inside the shed, and some statistics about the Pi itself. How does it work when the page is static HTML? This is where my newest pet project comes into play: Pyriodic Backend.

Pyriodic Backend is what it says in the name, it’s meant to be a very simple backend service, written in Python, for handling periodically updated data.

How it works is that the backend service runs every minute, powered by cron, and with every run, it loads the HTML files of website, and replaces the value of specific tags using the output of functions connected to those tags. Pyriodic Backend uses BeautifulSoup4 behind the scenes to do the HTML manipulation. The project is currently in a very early alpha stage, but as you can see, it is already being used “in production”. The repo is open source and under the GPL license. You can check it out on Codeberg, and if you would like to develop it with me, please feel free to create an issue or send me a PR. My goal is to make it a universal, very light and simple backend for static websites.

Pyriodic Backend on Codeberg.org

Next Steps

I’m already thinking on how to upgrade the system. Because of the large size of the solar panel, I am considering moving to a Pi 4b connected to the router via an ethernet cable. This should reduce a lot of the instability and latency caused by Wi-Fi. If the PV system starts having trouble with recharging the batteries during short winter days, I’ll just go back to the Zero. I would like to add much more things to the website, but then the bottleneck will be the speed of the Internet, and the limited data quota I have. My plan is to gradually add stuff, and see how the performance and data usage changes.

I also would like to add battery charge monitoring for the website. I already did a project focused on measuring the charge of 12V batteries:

How to monitor 12V battery charge with a Raspberry Pi Pico

but I need to find a way to connect it with the Pi and the backend.

And eventually I will move the house that is being built next to the shed, and when I have better Internet and equipment there, I will be able to expand my website even more.

Bottom Line

And that’s it! I haven’t been so excited with a project for a very long time. I feel that writing a website from scratch using the simplest possible technologies is a turning page for me, and gives me so much fun. And I am happy that I can share both the hardware plans, and the software with you, especially the Pyriodic Backend. I am hoping other people will use it for their projects. If you do, please let me know!

And being able to physically host a webserver offgrid, with the only requirements being the Sun and a bit of LTE coverage, I feel that it opens so many possibilities. And it feels both #SmallWeb and Solarpunk, two movements that are very dear to me.

If you want to build a similar off-grid server, and have any questions, just drop me an email, I will be happy to help :)

Thanks for reading!

If you enjoyed this post, please consider helping me make new projects by supporting me on the following crowdfunding sites: