Arch Linux
pacman -S algernon
Run Algernon in “dev” mode
This enables debug mode, uses the internal Bolt database, uses regular HTTP instead of HTTPS+HTTP/2 and enables caching for all files except: Pongo2, Amber, Lua, Teal, Sass, GCSS, Markdown and JSX.
algernon -e
Then try creating an index.lua
file with print("Hello, World!")
and visit the served web page in a browser.
Enable HTTP/2 in the browser (for older browsers)
- Chrome: go to
chrome://flags/#enable-spdy4
, enable, save and restart the browser. - Firefox: go to
about:config
, setnetwork.http.spdy.enabled.http2draft
totrue
. You might need the nightly version of Firefox.
Configure the required ports for local use
- You may need to change the firewall settings for port 3000, if you wish to use the default port for exploring the samples.
- For the auto-refresh feature to work, port 5553 must be available (or another host/port of your choosing, if configured otherwise).
Prepare for running the samples
git clone https://github.com/xyproto/algernon
make -C algernon
Launch the “welcome” page
- Run
./welcome.sh
to start serving the “welcome” sample. - Visit
http://localhost:3000/
Create your own Algernon application, for regular HTTP
mkdir mypage
cd mypage
- Create a file named
index.lua
, with the following contents:print("Hello, Algernon")
- Start
algernon --httponly --autorefresh
. - Visit
http://localhost:3000/
. - Edit
index.lua
and refresh the browser to see the new result. - If there were errors, the page will automatically refresh when
index.lua
is changed. - Markdown, Pongo2 and Amber pages will also refresh automatically, as long as
-autorefresh
is used.
Create your own Algernon application, for HTTP/2 + HTTPS
mkdir mypage
cd mypage
- Create a file named
index.lua
, with the following contents:print("Hello, Algernon")
- Create a self-signed certificate, just for testing:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3000 -nodes
- Press return at all the prompts, but enter
localhost
at Common Name. - For production, store the keys in a directory with as strict permissions as possible, then specify them with the
--cert
and--key
flags.
- Start
algernon
. - Visit
https://localhost:3000/
. - If you have not imported the certificates into the browser, nor used certificates that are signed by trusted certificate authorities, perform the necessary clicks to confirm that you wish to visit this page.
- Edit
index.lua
and refresh the browser to see the result (or a Lua error message, if the script had a problem).
There is also a small tutorial.
Using AI / LLMs / Ollama
- The
ollama
server must be running locally, or ahost:port
must be set in theOLLAMA_HOST
environment variable.
Example use, using the default tinyllama
model (will be downloaded at first use, the size is 637 MiB and it should run anywhere).
lua> ollama()
Autumn leaves, crisp air, poetry flowing - this is what comes to mind when I think of Algernon.
lua> ollama("Write a haiku about software developers")
The software developer,
In silence, tapping at keys,
Creating digital worlds.
Using OllamaClient
and the mixtral
model (will be downloaded at first use, the size is 26 GiB and it might require quite a bit of RAM and also a fast CPU and/or GPU).
”` lua> oc = OllamaClient(“mixtral”) lua> oc:ask(“Write a quicksort function in OCaml”) Sure! Here’s an implementation of the quicksort algorithm in OCaml:
let rec qsort = function | [] -> [] | pivot :: rest ->
let smaller, greater = List.partition (fun x -> x < pivot) rest in
qsort smaller @ [pivot] @ qsort greater
This function takes a list as input and returns a new list with the same elements but sorted in ascending order using the quicksort algorithm. The qsort
funct.
Here are some examples of using the qsort
function:
qsort [5; 2; 9; 1; 3];;
- : int list = [1; 2; 3; 5; 9]
qsort [“apple”; “banana”; “cherry”];;
- : string list = [“apple”; “banana”; “cherry”]
Set
// Get or create a database-backed Set (takes a name, returns a set object)
Set(string) -> userdata
// Add an element to the set
set:add(string)
// Remove an element from the set
set:del(string)
// Check if a set contains a value
// Returns true only if the value exists and there were no errors.
set:has(string) -> bool
// Get all members of the set
set:getall() -> table
// Remove the set itself. Returns true on success.
set:remove() -> bool
// Clear the set
set:clear() -> bool
List
// Get or create a database-backed List (takes a name, returns a list object)
List(string) -> userdata
// Add an element to the list
list:add(string)
// Get all members of the list
list:getall() -> table
// Get the last element of the list
// The returned value can be empty
list:getlast() -> string
// Get the N last elements of the list
list:getlastn(number) -> table
// Remove the list itself. Returns true on success.
list:remove() -> bool
// Clear the list. Returns true on success.
list:clear() -> bool
// Return all list elements (expected to be JSON strings) as a JSON list
list:json() -> string
HashMap
// Get or create a database-backed HashMap (takes a name, returns a hash map object)
HashMap(string) -> userdata
// For a given element id (for instance a user id), set a key
// (for instance "password") and a value.
// Returns true on success.
hash:set(string, string, string) -> bool
// For a given element id (for instance a user id), and a key
// (for instance "password"), return a value.
// Returns a value only if they key was found and if there were no errors.
hash:get(string, string) -> string
// For a given element id (for instance a user id), and a key
// (for instance "password"), check if the key exists in the hash map.
// Returns true only if it exists and there were no errors.
hash:has(string, string) -> bool
// For a given element id (for instance a user id), check if it exists.
// Returns true only if it exists and there were no errors.
hash:exists(string) -> bool
// Get all keys of the hash map
hash:getall() -> table
// Remove a key for an entry in a hash map
// (for instance the email field for a user)
// Returns true on success
hash:delkey(string, string) -> bool
// Remove an element (for instance a user)
// Returns true on success
hash:del(string) -> bool
// Remove the hash map itself. Returns true on success.
hash:remove() -> bool
// Clear the hash map. Returns true on success.
hash:clear() -> bool
Method 1
Follow the guide at certbot.eff.org for the “None of the above” web server, then start algernon
with --cert=/etc/letsencrypt/live/myhappydomain.com/cert.pem --key=/etc/letsencrypt/live/myhappydomain.com/privkey.pem
where myhappydomain.com
is replaced with your own domain name.
First make Algernon serve a directory for the domain, like /srv/myhappydomain.com
, then use that as the webroot when configuring certbot
with the certbot certonly
command.
Remember to set up a cron-job or something similar to run certbot renew
every once in a while (every 12 hours is suggested by certbot.eff.org). Also remember to restart the algernon service after updating the certificates.