# Little Beast
Simple, Pragmatic, Anti-bloat

![GitHub repo size](https://img.shields.io/github/repo-size/TechnicalSuwako/LittleBeast)
[![lines count](https://img.shields.io/endpoint?url=https://ghloc.vercel.app/api/TechnicalSuwako/LittleBeast/badge?filter=.php%24%2C.maron%24%2C.css%24&branch=master$)](https://ghloc.vercel.app/TechnicalSuwako/LittleBeast?filter=.php%24%2C.maron%24%2C.css%24)

Demo installation: [https://lbdemo.technicalsuwako.moe/](https://lbdemo.technicalsuwako.moe/)

## What is Little Beast?
Little Beast is a PHP 8.3 or above framework made for 076.moe (game developer company) and technicalsuwako.moe (CEO's blog).\
The core mentality is to extend what you need, and remove what you don't need.\
Each core feature is split into libraries, so it is easy to choose what you need.\
All modules are written from scratch, nothing is to be require a database.

Little Beast is TechnicalSuwako's final web project before moving back to game development completely.

## What Little Beast is not?
* General purpose framework
* Hard to use
* Meant for web developers
* For everyone/wider audience
* Tedious to install
* Dogmatic
* Democratically run

## What Little Beast has not?
* Database (everything is a file)
* Dependencies
* Package manager
* Docker/Kubernetes/Vagrant/Nix/etc containers
* Javascript
* Bloatware
* ORM
* Authentication/authorization system
* Queues or background job
* Cloud/Serverless integration
* Scaffolding
* Code generation
* Abstraction layers
* Unnecessary files
* DEI, Code of Conduct, or other discriminatory practises

## Unique features
* No database
* No Composer or PEAR
* No server overhead
* No container
* Maron template engine
* Custom Markdown
* ActivityPub
* Multi-language support
* Multi-blog support
* 100% correct and beautiful HTML5 and CSS3
* 100% correct PHP
* SEO friendly
* Modular CSS
* Atom feeds
* Built-in test suite

## How to install
```sh
cd /var/www/htdocs
git clone https://github.com/TechnicalSuwako/LittleBeast.git .
mv config/config.sample.php config/config.php
```

Configure HTTP server to run `/public` as root via php-fpm.\
That's all!

### OpenBSD server
```sh
pkg_add php-8.4.14 php-gmp-8.4.14
rcctl enable php84_fpm httpd relayd
rcctl start php84_fpm httpd relayd
```

#### httpd
```
server "technicalsuwako.moe" {
  listen on * tls port 8443
  gzip-static
  tls {
    certificate "/etc/ssl/technicalsuwako.moe.crt"
    key "/etc/ssl/private/technicalsuwako.moe.key"
  }
  root "/htdocs/technicalsuwako.moe/www/public"
  directory index "index.php"
  location "/.well-known/acme-challenge/*" {
    root "/acme"
    request strip 2
  }

  location "/*.php" {
    fastcgi socket "/run/php-fpm.sock"
  }

  location "/*.php[/?]*" {
    fastcgi socket "/run/php-fpm.sock"
  }

  location "/" {
    directory index "index.php"
  }
  location match "/blog/" {
    request rewrite "/index.php"
  }
  location match "/about" {
    request rewrite "/index.php"
  }
  location match "/monero" {
    request rewrite "/index.php"
  }
  location match "/secret" {
    request rewrite "/index.php"
  }
  location match "/ap/" {
    request rewrite "/index.php"
  }
  location "/.well-known/webfinger" {
    request rewrite "/index.php"
  }
  location "/blog.atom" {
    request rewrite "/index.php"
  }
}

server "www.technicalsuwako.moe" {
  listen on * tls port 8443
  gzip-static
  tls {
    certificate "/etc/ssl/technicalsuwako.moe.crt"
    key "/etc/ssl/private/technicalsuwako.moe.key"
  }
  block return 301 "https://technicalsuwako.moe$REQUEST_URI"
}
```

#### relayd
```
relayd_addr="0.0.0.0"
router_addr="192.168.10.106"

table <httpd> { $router_addr }

http protocol reverse {
  tcp { nodelay, sack, socket buffer 65536, backlog 100 }
  tls ciphers "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
  tls keypair "technicalsuwako.moe"

  return error

  match request header append "X-Forwarded-For" value "$REMOTE_ADDR"
  match request header append "X-Forwarded-Port" value "$REMOTE_PORT"

  #match response header set "Referrer-Policy" value "same-origin"
  match response header set "X-Frame-Options" value "deny"
  match response header set "X-Content-Type-Options" value "nosniff"
  match response header set "Referrer-Policy" value "strict-origin-when-cross-origin"
  match response header set "Strict-Transport-Security" value "max-age=31536000; includeSubDomains; preload"
  match response header set "Cross-Origin-Opener-Policy" value "same-origin"
  match response header set "Content-Security-Policy" value "img-src 'self' https://*.076.moe http://*.076.moe https://*.technicalsuwako.moe http://*.technicalsuwako.moe; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; object-src 'none';"
  match response header append "Permissions-Policy" value "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=()"

  match request header "Accept-Encoding" value "gzip" tag "gzip"
  match response header "Content-Type" value "text/*" tag "compress"
  match response header "Content-Type" value "text/html" tag "charset=UTF-8"
  match response header "Content-Type" value "application/javascript" tag "compress"
  match response header "Content-Type" value "application/json" tag "compress"

  pass request quick header "Host" value "technicalsuwako.moe" forward to <httpd>

  pass
}

relay www_tls {
  listen on $relayd_addr port 443 tls
  protocol reverse

  # Default
  forward to <httpd> port 8443 check tcp
}

relay www_www {
  listen on $relayd_addr port 80
  protocol reverse

  # Default
  forward to <httpd> port 8080 check tcp
}
```

## Required PHP module
* php_gmp
