summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2025-06-21 10:14:31 +0200
committerMarc Vertes <mvertes@free.fr>2025-06-21 10:14:31 +0200
commit0b09eab4f26d3fdb4f210156640be6e8dfcc238f (patch)
tree693057ce5b5e2f46ef4e0b5be6226dd0c14f69a9
initial commit
-rw-r--r--Makefile12
-rwxr-xr-xbuild.sh235
-rw-r--r--favicon.pngbin0 -> 601 bytes
-rw-r--r--feed.xml37
-rwxr-xr-xgenrss.sh50
-rw-r--r--index.html47
-rw-r--r--meta.sh6
-rw-r--r--readme.md15
-rw-r--r--this-server/a_web_server_on_a_solar_phone.md55
-rw-r--r--this-server/index.html48
-rw-r--r--this-server/meta.sh6
-rw-r--r--this-server/server.jpegbin0 -> 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(/&amp;/, "\\&", href)
+ gsub(/&lt;/, "<", href)
+ gsub(/&gt;/, ">", 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("&", "\\&amp;")
+ gsub("<", "\\&lt;")
+ gsub(">", "\\&gt;")
+ }
+
+ # 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>. &emsp; &emsp; 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
new file mode 100644
index 0000000..d7cb86d
--- /dev/null
+++ b/favicon.png
Binary files differ
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>. &emsp; &emsp; Licensed under
+<a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.
+</div>
diff --git a/meta.sh b/meta.sh
new file mode 100644
index 0000000..e6d75fe
--- /dev/null
+++ b/meta.sh
@@ -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.
+
+![The server with its solar panel, and a cat](server.jpeg)
+
+## 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
new file mode 100644
index 0000000..e1a1427
--- /dev/null
+++ b/this-server/server.jpeg
Binary files differ