diff options
| author | Marc Vertes <mvertes@free.fr> | 2025-06-21 10:14:31 +0200 |
|---|---|---|
| committer | Marc Vertes <mvertes@free.fr> | 2025-06-21 10:14:31 +0200 |
| commit | 0b09eab4f26d3fdb4f210156640be6e8dfcc238f (patch) | |
| tree | 693057ce5b5e2f46ef4e0b5be6226dd0c14f69a9 | |
initial commit
| -rw-r--r-- | Makefile | 12 | ||||
| -rwxr-xr-x | build.sh | 235 | ||||
| -rw-r--r-- | favicon.png | bin | 0 -> 601 bytes | |||
| -rw-r--r-- | feed.xml | 37 | ||||
| -rwxr-xr-x | genrss.sh | 50 | ||||
| -rw-r--r-- | index.html | 47 | ||||
| -rw-r--r-- | meta.sh | 6 | ||||
| -rw-r--r-- | readme.md | 15 | ||||
| -rw-r--r-- | this-server/a_web_server_on_a_solar_phone.md | 55 | ||||
| -rw-r--r-- | this-server/index.html | 48 | ||||
| -rw-r--r-- | this-server/meta.sh | 6 | ||||
| -rw-r--r-- | this-server/server.jpeg | bin | 0 -> 64598 bytes |
12 files changed, 511 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4041406 --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +# Generate the static web site from markdown files. +build: + ./build.sh + ./genrss.sh > feed.xml + +# Launch a local web server. +server: + yaegi -e 'http.ListenAndServe(":8080", http.FileServer(http.Dir(".")))' + +# Publish on github pages. +publish: + git push diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..166eeba --- /dev/null +++ b/build.sh @@ -0,0 +1,235 @@ +#!/bin/sh + +header='<meta charset="UTF-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<style> + body { + max-width: 45rem; + margin: auto; + padding: 0.5em; + text-align: justify; + } + h1 { text-align: center } + pre { + padding: 1ch; + background-color: #f5f5f5; + overflow: auto; + } + img { + display: block; + margin: auto; + } + .footer { + text-align: center; + font-size: 0.8em; + } +</style> +' + +md2html() { +# Usage: +# md2html file.md > file.html +# Options: -v esc=false to not escape html +awk ' + function newblock(nblock) { + if (text) + print "<" block ">" text "</" block ">" + text = "" + block = nblock ? nblock : "p" + } + + function subinline(tgl, inl) { + while (match($0, tgl)){ + if (inline[ni] == inl) + ni -= sub(tgl, "</" inl ">") + else if (sub(tgl, "<" inl ">")) + inline[++ni] = inl + } + } + + function dolink(href, lnk) { + # Undo escaped html in uris + gsub(/&/, "\\&", href) + gsub(/</, "<", href) + gsub(/>/, ">", href) + # & can be tricky, and not standard: + gsub(/&/, "\\\\\\&", href) + gsub(/&/, "\\\\\\&", lnk) + return "<a href=\"" href "\">" lnk "</a>" + } + + BEGIN { + ni = 0; # inlines + nl = 0; # nested lists + text = "" + block = "p" + } + + # Escape html + esc != "false" { + gsub("&", "\\&") + gsub("<", "\\<") + gsub(">", "\\>") + } + + # Horizontal rules (_ is not in markdown) + /^[ ]*([-*_] ?)+[ ]*$/ && text == "" { + print "<hr>" + next + } + + # Tables (not in markdown) + # Syntax: + # Right Align| Center Align |Left Align + /([ ]\|)|(\|[ ])/ { + if (block != "table") + newblock("table") + nc = split($0, cells, "|") + $0 = "<tr>\n" + for (i = 1; i <= nc; i++){ + align = "left" + if (sub(/^[ ]+/, "", cells[i])){ + if (sub(/[ ]+$/, "", cells[i])) + align = "center" + else + align = "right" + } + sub(/[ ]+$/,"", cells[i]) + $0 = $0 "<td align=\"" align "\">" cells[i] "</td>\n" + } + $0 = $0 "</tr>" + } + + # Ordered and unordered (possibly nested) lists + /^[ ]*([*+-]|(([0-9]+[\.-]?)+))[ ]/ { + newblock("li") + nnl = 1 + while (match($0, /^[ ]/)){ + sub(/^[ ]/,"") + nnl++ + } + while (nl > nnl) + print "</" list[nl--] ">" + while (nl < nnl){ + list[++nl] = "ol" + if (match($0, /^[*+-]/)) + list[nl] = "ul" + print "<" list[nl] ">" + } + sub(/^([*+-]|(([0-9]+[\.-]?)+))[ ]/,"") + } + + # Multi line list items + block == "li" { + sub(/^( *)|( *)/,"") + } + + # Code blocks + /^( | )/ { + if (block != "code") + newblock("code") + sub(/^( | )/, "") + text = text $0 "\n" + next + } + + # Paragraphs + /^$/ { + newblock() + while (nl > 0) + print "</" list[nl--] ">" + } + + # Headers + /^#/ { + newblock() + match($0, /#+/) + n = RLENGTH + if (n > 6) + n = 6 + text = substr($0, RLENGTH + 1) + block = "h" n + next + } + + # Alternate headers (underlined) + /^=+$/ { + block = "h" 1 + next + } + + /^-+$/ { + block = "h" 2 + next + } + + { + # Images + while (match($0, /!\[[^\]]+\]\([^\)]+\)/)){ + split(substr($0, RSTART, RLENGTH), a, /(!\[)|\)|(\]\()/) + sub(/!\[[^\]]+\]\([^\)]+\)/, "<img src=\"" a[3] "\" alt=\"" a[2] "\">") + } + # Links + while (match($0, /\[[^\]]+\]\([^\)]+\)/)){ + split(substr($0, RSTART, RLENGTH), a, /[\[\)]|(\]\()/) + sub(/\[[^\]]+\]\([^\)]+\)/, dolink(a[3], a[2])) + } + # Auto links (uri matching is poor) + na = split($0, a, /(^\()|[ ]|([,\.\)]([ ]|$))/) + for (i = 1; i <= na; i++) + if (match(a[i], /^(((https?|ftp|file|news|irc):\/\/)|(mailto:)).+$/)) + sub(a[i], dolink(a[i], a[i])) + # Inline + subinline("(\\*\\*)|(__)", "strong") + subinline("\\*", "em") + subinline("`", "code") + text = text (text ? " " : "") $0 + } + + END { + while (ni > 0) + text = text "</" inline[ni--] ">" + newblock() + while (nl > 0) + print "</" list[nl--] ">" + }' "$1" +} + +genhtml() ( + cd "$1" || return + + . ./meta.sh + + exec 1>index.html + + # Header + echo "<!DOCTYPE html>" + echo "<!-- generated by build.sh. DO NOT EDIT. -->" + echo "<html lang=\"${lang:-en}\">" + echo "<title>$title</title>" + [ "$description" ] && echo "<meta name=\"description\" content=\"$description\">" + echo "$header" + [ "$1" != . ] && echo "<a href=\"..\">$blog_title</a><hr>" + + # Body + # pandoc *.md + for f in *.md; do + [ -f "$f" ] && md2html "$f" + done + + # Footer + [ "$1" != . ] && echo "<hr>From: $author, $date" +) + +for d in *; do + [ -d "$d" ] && genhtml "$d" +done +genhtml . + +# Fix for mastodon. +sed '/mstdn/s/href=/rel="me" href=/' index.html >xx && mv xx index.html +# Put a license in index footer. +echo '<hr><div class="footer"> +<a href="feed.xml">RSS feed</a>.     Licensed under +<a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>. +</div>' >>index.html diff --git a/favicon.png b/favicon.png Binary files differnew file mode 100644 index 0000000..d7cb86d --- /dev/null +++ b/favicon.png diff --git a/feed.xml b/feed.xml new file mode 100644 index 0000000..f973500 --- /dev/null +++ b/feed.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"> +<channel> +<title>Marc's Notes</title> +<link>https://dot.vertes.org/</link> +<description>An experimental website on a solar phone</description> +<managingEditor>marc@vertes.org (Marc Vertes)</managingEditor> +<pubDate>Fri, 20 Jun 2025 16:58:13 +0200</pubDate> +<item> +<guid isPermaLink="true">https://dot.vertes.org/this-server/</guid> +<title>A web server on a solar phone</title> +<link>https://dot.vertes.org/this-server/</link> +<description>Hosting a web server on a solar powered phone</description> +<author>marc@vertes.org (Marc Vertes)</author> +<pubDate>Fri, 20 June 2025 12:00:00 +0200</pubDate> +<content:encoded> +<![CDATA[<h1> A web server on a solar phone</h1> +<p>I have this old low-cost phone which was the first one offered to my kid when he was 15 (he is now 21), before he moved to a more fashionable model. I noticed that without a SIM card, only on WIFI, the phone needed to be recharged not after 1 or 2 days, but only after 2 weeks! So this small device, plugged to a small solar panel, could be the perfect always-on personal web server. The site that you are browsing right now is hosted on it.</p> +<p><img src="https://dot.vertes.org/this-server/server.jpeg" alt="The server with its solar panel, and a cat"></p> +<h2> Hardware</h2> +<p>The phone is an entry-level Motorola G7 Play, purchased in 2019 for 120€ or so, worth nothing today. It was used by my son for less than 2 years, then dormant since. The display is slighly shattered, but it doesn't matter, as I use it headless.</p> +<p>I bought a small solar panel on Amazon, 10W produced by 2 plates of 17x17 cm. Cost: 28€. I could probably get something less expensive.</p> +<p>And that's it. The solar panel is just suspended vertically at a south window. The phone sits below, connected to the panel by a USB cable, in the shadow (do not put the phone directly under the sun, or closed without fresh air).</p> +<h2> Software</h2> +<p>The single purpose of this device is now to run a small standalone static web server. By using termux on top of Android, I can run a ssh server for remote access and Nginx, an efficient web server. I do not need to root the phone, as port redirection from my internet router compensate for the restriction of not using a port number below 1024.</p> +<p>Nevertheless, I installed LineageOS on the phone, as it supports my model and keeps the system updated. I could have kept the stock android image, at the expanse of a less secure system. I could have gone further and install PostmarketOS on it, to have a full unrestricted Linux machine, but I was both lazy and curious to see what I could get from just Android.</p> +<p>I then installed F-Droid, only to install Termux from it. Do not install Termux from the Google Play Store, it is too limited. The version from F-Droid is fine.</p> +<p>The phone connects to my internet box via WIFI and my internet service provider allows me to have a static IP4 address at no additional cost.</p> +<p>The last part is to configure the SSL certificate. I used Acme.sh, downloaded directly from Github.</p> +<h2> Operation</h2> +<p>It's too early to say. Lets see how it goes over time (a few months), and if a relatively old phone can find a second life and be used as an autonomous web server, running solely on free photons and electrons.</p> +<p>But for now, we are in june and the battery level is almost always at 100%.</p> +<hr>From: Marc Vertes, 20 june 2025]]> +</content:encoded> +</item> +</channel> +</rss> diff --git a/genrss.sh b/genrss.sh new file mode 100755 index 0000000..f92c1ac --- /dev/null +++ b/genrss.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +fixhtml() { + gawk ' + # Skip everything before first <h1>. + /<h1/ { p = !p } + p { + # Make reference links absolute. + $0 = gensub(/<img src="([^hH][^"]*)"/, "<img src=\"'$1'\\1\"", "g") + $0 = gensub(/<a href="([^hH][^"]*)"/, "<a href=\"'$1'\\1\"", "g") + print + } + ' "$2" +} + +. ./meta.sh +cat <<- EOT + <?xml version="1.0" encoding="UTF-8"?> + <rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"> + <channel> + <title>$title</title> + <link>$link/</link> + <description>$description</description> + <managingEditor>$email ($author)</managingEditor> + <pubDate>$(date -R)</pubDate> +EOT + +for d in *; do + [ -d "$d" ] || continue + cd $d + . ./meta.sh + cat <<- EOT + <item> + <guid isPermaLink="true">$link/$d/</guid> + <title>$title</title> + <link>$link/$d/</link> + <description>$description</description> + <author>$email ($author)</author> + <pubDate>$date_rfc2822</pubDate> + <content:encoded> + <![CDATA[$(fixhtml "$link/$d/" index.html)]]> + </content:encoded> + </item> + EOT +done + +cat <<- EOT + </channel> + </rss> +EOT diff --git a/index.html b/index.html new file mode 100644 index 0000000..7029132 --- /dev/null +++ b/index.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<!-- generated by build.sh. DO NOT EDIT. --> +<html lang="en"> +<title>Marc's Notes</title> +<meta name="description" content="An experimental website on a solar phone"> +<meta charset="UTF-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<style> + body { + max-width: 45rem; + margin: auto; + padding: 0.5em; + text-align: justify; + } + h1 { text-align: center } + pre { + padding: 1ch; + background-color: #f5f5f5; + overflow: auto; + } + img { + display: block; + margin: auto; + } + .footer { + text-align: center; + font-size: 0.8em; + } +</style> + +<h1> Marc's Notes</h1> +<p>A blog about programming and other stories.</p> +<h2> Posts</h2> +<ul> +<li><a href="this-server">About this server</a> june 2025</li> +</ul> +<p> A web server on an old smartphone, solar powered.</p> +<h2> Contact</h2> +<ul> +<li>Email: marc@vertes.org</li> +<li>Github: <a href="https://github.com/mvertes">@mvertes</a></li> +<li>Mastodon: <a rel="me" href="https://mstdn.fr/@mvertes">@mvertes</a></li> +</ul> +<hr><div class="footer"> +<a href="feed.xml">RSS feed</a>.     Licensed under +<a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>. +</div> @@ -0,0 +1,6 @@ +title="Marc's Notes" +author="Marc Vertes" +email="marc@vertes.org" +description="An experimental website on a solar phone" +link="https://dot.vertes.org" +date="20 th of June 2025" diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..81a4acf --- /dev/null +++ b/readme.md @@ -0,0 +1,15 @@ +# Marc's Notes + +A blog about programming and other stories. + +## Posts + +- [About this server](this-server) june 2025 + + A web server on an old smartphone, solar powered. + +## Contact + +* Email: marc@vertes.org +* Github: [@mvertes](https://github.com/mvertes) +* Mastodon: [@mvertes](https://mstdn.fr/@mvertes) diff --git a/this-server/a_web_server_on_a_solar_phone.md b/this-server/a_web_server_on_a_solar_phone.md new file mode 100644 index 0000000..ad2757b --- /dev/null +++ b/this-server/a_web_server_on_a_solar_phone.md @@ -0,0 +1,55 @@ +# A web server on a solar phone + +I have this old low-cost phone which was the first one offered to my kid when +he was 15 (he is now 21), before he moved to a more fashionable model. I +noticed that without a SIM card, only on WIFI, the phone needed to be recharged +not after 1 or 2 days, but only after 2 weeks! So this small device, plugged to +a small solar panel, could be the perfect always-on personal web server. The +site that you are browsing right now is hosted on it. + + + +## Hardware + +The phone is an entry-level Motorola G7 Play, purchased in 2019 for 120€ or so, +worth nothing today. It was used by my son for less than 2 years, then dormant +since. The display is slighly shattered, but it doesn't matter, as I use it +headless. + +I bought a small solar panel on Amazon, 10W produced by 2 plates of 17x17 cm. +Cost: 28€. I could probably get something less expensive. + +And that's it. The solar panel is just suspended vertically at a south window. +The phone sits below, connected to the panel by a USB cable, in the shadow +(do not put the phone directly under the sun, or closed without fresh air). + +## Software + +The single purpose of this device is now to run a small standalone static web +server. By using termux on top of Android, I can run a ssh server for remote +access and Nginx, an efficient web server. I do not need to root the phone, as +port redirection from my internet router compensate for the restriction of not +using a port number below 1024. + +Nevertheless, I installed LineageOS on the phone, as it supports my model and +keeps the system updated. I could have kept the stock android image, at the +expanse of a less secure system. I could have gone further and install PostmarketOS +on it, to have a full unrestricted Linux machine, but I was both lazy and curious +to see what I could get from just Android. + +I then installed F-Droid, only to install Termux from it. Do not install Termux +from the Google Play Store, it is too limited. The version from F-Droid is fine. + +The phone connects to my internet box via WIFI and my internet service provider +allows me to have a static IP4 address at no additional cost. + +The last part is to configure the SSL certificate. I used Acme.sh, +downloaded directly from Github. + +## Operation + +It's too early to say. Lets see how it goes over time (a few months), and if a +relatively old phone can find a second life and be used as an autonomous web +server, running solely on free photons and electrons. + +But for now, we are in june and the battery level is almost always at 100%. diff --git a/this-server/index.html b/this-server/index.html new file mode 100644 index 0000000..019b7db --- /dev/null +++ b/this-server/index.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<!-- generated by build.sh. DO NOT EDIT. --> +<html lang="en"> +<title>A web server on a solar phone</title> +<meta name="description" content="Hosting a web server on a solar powered phone"> +<meta charset="UTF-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<style> + body { + max-width: 45rem; + margin: auto; + padding: 0.5em; + text-align: justify; + } + h1 { text-align: center } + pre { + padding: 1ch; + background-color: #f5f5f5; + overflow: auto; + } + img { + display: block; + margin: auto; + } + .footer { + text-align: center; + font-size: 0.8em; + } +</style> + +<a href="..">Marc's Notes</a><hr> +<h1> A web server on a solar phone</h1> +<p>I have this old low-cost phone which was the first one offered to my kid when he was 15 (he is now 21), before he moved to a more fashionable model. I noticed that without a SIM card, only on WIFI, the phone needed to be recharged not after 1 or 2 days, but only after 2 weeks! So this small device, plugged to a small solar panel, could be the perfect always-on personal web server. The site that you are browsing right now is hosted on it.</p> +<p><img src="server.jpeg" alt="The server with its solar panel, and a cat"></p> +<h2> Hardware</h2> +<p>The phone is an entry-level Motorola G7 Play, purchased in 2019 for 120€ or so, worth nothing today. It was used by my son for less than 2 years, then dormant since. The display is slighly shattered, but it doesn't matter, as I use it headless.</p> +<p>I bought a small solar panel on Amazon, 10W produced by 2 plates of 17x17 cm. Cost: 28€. I could probably get something less expensive.</p> +<p>And that's it. The solar panel is just suspended vertically at a south window. The phone sits below, connected to the panel by a USB cable, in the shadow (do not put the phone directly under the sun, or closed without fresh air).</p> +<h2> Software</h2> +<p>The single purpose of this device is now to run a small standalone static web server. By using termux on top of Android, I can run a ssh server for remote access and Nginx, an efficient web server. I do not need to root the phone, as port redirection from my internet router compensate for the restriction of not using a port number below 1024.</p> +<p>Nevertheless, I installed LineageOS on the phone, as it supports my model and keeps the system updated. I could have kept the stock android image, at the expanse of a less secure system. I could have gone further and install PostmarketOS on it, to have a full unrestricted Linux machine, but I was both lazy and curious to see what I could get from just Android.</p> +<p>I then installed F-Droid, only to install Termux from it. Do not install Termux from the Google Play Store, it is too limited. The version from F-Droid is fine.</p> +<p>The phone connects to my internet box via WIFI and my internet service provider allows me to have a static IP4 address at no additional cost.</p> +<p>The last part is to configure the SSL certificate. I used Acme.sh, downloaded directly from Github.</p> +<h2> Operation</h2> +<p>It's too early to say. Lets see how it goes over time (a few months), and if a relatively old phone can find a second life and be used as an autonomous web server, running solely on free photons and electrons.</p> +<p>But for now, we are in june and the battery level is almost always at 100%.</p> +<hr>From: Marc Vertes, 20 june 2025 diff --git a/this-server/meta.sh b/this-server/meta.sh new file mode 100644 index 0000000..60682cc --- /dev/null +++ b/this-server/meta.sh @@ -0,0 +1,6 @@ +blog_title="Marc's Notes" +title="A web server on a solar phone" +author="Marc Vertes" +description="Hosting a web server on a solar powered phone" +date="20 june 2025" +date_rfc2822="Fri, 20 June 2025 12:00:00 +0200" diff --git a/this-server/server.jpeg b/this-server/server.jpeg Binary files differnew file mode 100644 index 0000000..e1a1427 --- /dev/null +++ b/this-server/server.jpeg |
