Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
include $(FAB_PATH)/common/mk/turnkey/web2py.mk

# The shared Web2py configuration follows an unpinned latest-release lookup.
# Keep its Trixie packages and overlays, but install the pinned supported source
# from this appliance instead.
COMMON_CONF := $(filter-out web2py,$(COMMON_CONF))

include $(FAB_PATH)/common/mk/turnkey.mk
12 changes: 7 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,18 @@ and on top of that:

- web2py configurations:

- Installed from upstream source code to /var/www/web2py
- Web2py 3 is installed from a pinned official upstream release in
``/var/www/web2py``.

**Security note**: Updates to web2py may require supervision so
they **ARE NOT** configured to install automatically. Using the "upgrade
now" button (within the webUI admin area) is the easiest way. Otherwise,
please see the `web2py documentation`_ for further info on
upgrading.
they **ARE NOT** configured to install automatically. Run
``web2py-update --check`` to inspect the supported Web2py 3 channel.
Back up the appliance and review the upstream changes before running
``web2py-update --apply``.

- Serve web2py applications with WSGI on Apache.
- Force admin console to be served via SSL.
- Include a MariaDB connection for database-driven Web2py applications.

- SSL support out of the box.
- Postfix MTA (bound to localhost) to allow sending of email (e.g.,
Expand Down
14 changes: 14 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
turnkey-web2py-19.0 (1) turnkey; urgency=low

* Install the supported Web2py 3.3.3 release from its pinned official Git
tag and recorded submodule commits.

* Add a supervised Web2py 3.x update command.

* Preserve the Apache WSGI, HTTPS administration, and MariaDB application
boundaries on Debian 13 Trixie.

* See turnkey-core's 19.0 changelog for common platform changes.

-- TurnKey Linux maintainers <release@turnkeylinux.org> Tue, 25 Aug 2026 00:00:00 +0000

turnkey-web2py-18.0 (1) turnkey; urgency=low

* Install web2py from upstream git: v2.27.1.
Expand Down
99 changes: 96 additions & 3 deletions conf.d/main
Original file line number Diff line number Diff line change
@@ -1,11 +1,104 @@
#!/bin/bash -ex
#!/bin/bash -e

set -x

VERSION=3.3.3
TAG=v3.3.3
COMMIT=a729b848ff6b6471a2792cae8156bf087afc2456
PYDAL_COMMIT=b515c362e83006e79f681ff6491e4a4ab8566acb
ROCKET_COMMIT=4154030489ebab15b96d1f90a6f288cf4f64dd23
YATL_COMMIT=c6983a51909f76c48f4a40c93eea7f485321cd3f
REMOTE=https://github.com/web2py/web2py.git
W2PROOT=/var/www/web2py
DB_NAME=web2py
DB_USER=web2py

install -d -m 0755 "$W2PROOT"
git -C "$W2PROOT" init
git -C "$W2PROOT" remote add origin "$REMOTE"
git -C "$W2PROOT" fetch --depth 1 origin "refs/tags/$TAG:refs/tags/$TAG"
git -C "$W2PROOT" checkout --detach "$TAG"
test "$(git -C "$W2PROOT" rev-parse HEAD)" = "$COMMIT"
git -C "$W2PROOT" submodule update --init --recursive --depth 1
test "$(git -C "$W2PROOT/gluon/packages/pydal" rev-parse HEAD)" = \
"$PYDAL_COMMIT"
test "$(git -C "$W2PROOT/gluon/packages/rocket3" rev-parse HEAD)" = \
"$ROCKET_COMMIT"
test "$(git -C "$W2PROOT/gluon/packages/yatl" rev-parse HEAD)" = \
"$YATL_COMMIT"
git -C "$W2PROOT" fsck --no-dangling

# Expose the official WSGI entry point through the shared Apache overlay.
cp "$W2PROOT/handlers/wsgihandler.py" "$W2PROOT/wsgihandler.py"

# set welcome as web2py default application
cat >$W2PROOT/routes.py<<EOF
cat >"$W2PROOT/routes.py" <<'EOF'
#!/usr/bin/env python
default_application = 'welcome'
EOF

chown www-data:www-data $W2PROOT/routes.py
service mysql start
mysqladmin create "$DB_NAME"

# Keep the persistent application credentials out of the build trace.
set +x
DB_PASS=$(mcookie)
mysql --batch <<EOF
CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';
GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';
USE $DB_NAME;
CREATE TABLE turnkey_status (
id INT PRIMARY KEY,
message VARCHAR(128) NOT NULL
);
INSERT INTO turnkey_status (id, message)
VALUES (1, 'Database connectivity verified');
FLUSH PRIVILEGES;
EOF
cat >"$W2PROOT/.turnkey-db" <<EOF
DATABASE_URL=mysql://$DB_USER:$DB_PASS@127.0.0.1:3306/$DB_NAME
EOF
chmod 0640 "$W2PROOT/.turnkey-db"
chown root:www-data "$W2PROOT/.turnkey-db"
unset DB_PASS
set -x

install -d -m 0755 /usr/local/share/turnkey-web2py
cat >/usr/local/share/turnkey-web2py/source <<EOF
version=$VERSION
tag=$TAG
commit=$COMMIT
pydal_commit=$PYDAL_COMMIT
rocket_commit=$ROCKET_COMMIT
yatl_commit=$YATL_COMMIT
remote=$REMOTE
EOF

# Seed the database-backed runtime before firstboot rotates common credentials.
python3 - "$W2PROOT" <<'PY'
import sys

root = sys.argv[1]
sys.path.insert(0, root)
from gluon import DAL

with open(f"{root}/.turnkey-db", encoding="utf-8") as stream:
uri = stream.read().strip().split("=", 1)[1]
db = DAL(uri, migrate=False)
rows = db.executesql("SELECT message FROM turnkey_status WHERE id = 1")
assert len(rows) == 1
assert rows[0][0] == "Database connectivity verified"
db.close()
PY

chown -R www-data:www-data "$W2PROOT"
chown root:www-data "$W2PROOT/.turnkey-db"
chmod 0640 "$W2PROOT/.turnkey-db"

/usr/lib/inithooks/bin/web2py.py --pass=turnkey

a2dissite 000-default
a2ensite web2py
a2enmod rewrite

service mysql stop
79 changes: 79 additions & 0 deletions docs/v19.0-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Web2py v19 acceptance

## Source and support boundary

Debian Trixie does not package the Web2py framework. The appliance installs
the official Web2py 3.3.3 Git tag at commit
`a729b848ff6b6471a2792cae8156bf087afc2456`. The build also verifies the
exact PyDAL, Rocket3, and YATL commits recorded by that tag. Web2py 3.x is the
upstream-supported Python 3 line in limited maintenance; the 2.27.1 line used
by v18 is end of life. Python, Apache, mod_wsgi, MariaDB, and the MySQL driver
come from Debian Trixie.

## README crosswalk

| Contract | Focused acceptance | Required result |
| --- | --- | --- |
| Web2py source installation | Compare the runtime version, Git commit, submodule commits, and tracked worktree | Official Web2py 3.3.3 and its recorded source tree run unchanged |
| Sample application | Request the default welcome application through Apache HTTP and HTTPS | Both responses contain the Web2py success marker |
| Secure administration | Follow the HTTP admin redirect, submit the firstboot password over HTTPS, and open the site manager | HTTP redirects to HTTPS and the authenticated page lists installed applications |
| Database-driven applications | Query a seeded MariaDB row through Web2py's DAL and directly through MariaDB | Both paths return the exact status value |
| WSGI on Apache | Require active Apache, a valid configuration, and live dynamic requests | Apache serves the Web2py WSGI handler successfully |
| Supervised updates | Run `web2py-update --check` and `--apply --dry-run` | The official supported 3.x tag and commit are selected without changing the installation |
| Inherited administration | Cite the unchanged Core 19 baseline for SSH, Webmin, Postfix, and common platform behavior | Core 19 PASS run `20260824t010251z-1634-32241` at source `24c82ee3540ce545422742b0e28ba6b687c53ec2` remains applicable |

## Exact acceptance

```sh
TKLDEV_CONTAINER=tkldev19-wave2 \
TKL_HARNESS_STATE_DIR=/home/agent/.local/state/turnkey-v19-harness-wave2 \
TKL_HARNESS_LOCK_FILE=/home/agent/.local/state/turnkey-v19-harness-wave2/build.lock \
TKL_HARNESS_LOCK_TIMEOUT=3600 \
TKL_HARNESS_DOCKER_LIMIT_BYTES=42949672960 \
/sandboxed-git/turnkey/tools/test-v19-appliance web2py \
--source /home/agent/.local/worktrees/turnkey-apps/web2py/wish-web2py-v19-trixie
```

Retained run `20260826t031723z-720-6453` passed this command against source
commit `0a200200f777813c18b50c2635a10fa5e3a57edf` and harness commit
`54ca2cff6b98a034089d186b249835b58fc467da`. The commit and transport archive
SHA-256 were both
`8ea9b63cca7935411696da3bad2392735808b6ade1710b67f6868185ef7f38c4`.
The input tree SHA-256 was
`ea1dcccd594e69bb4db2ad51386702ca3ffb77d598b77a01f782078c3f09d235`,
and the build tree SHA-256 was
`2bbac7162e4bcde1ba26580d7c22d86c5a786eabd3391455726e97f4805532ba`.
The run built the Trixie root, used the documented `root.patched` overlayfs
fallback, completed normal init and firstboot, and passed the HTTP and HTTPS
welcome requests, HTTPS administrator login, Web2py DAL and direct MariaDB
readback, and updater check and dry run. The installed runtime was Web2py 3.3.3
on Python 3.13.5. The updater reported 3.3.3 at commit
`a729b848ff6b6471a2792cae8156bf087afc2456` as up to date. Runtime tests and
cleanup passed, and the retained verdict is `PASS` with exit status 0.

## Disposable updater apply proof

The updater's real apply and provenance branch was exercised with local tagged
repositories using:

```sh
sudo env \
WEB2PY_TEST_SCRATCH_ROOT=/home/agent/.local/state/turnkey-web2py-test \
./tests/web2py-update-apply.sh
```

The command completed successfully after advancing the fixture from v3.3.3 to
v3.3.4. Its assertions verified the matching top-level and three submodule
revisions, clean source trees, serialized provenance, and Apache service
recovery.

## Deferred issues

- Web2py 3.x receives limited maintenance and is not recommended for new
projects. The appliance preserves supported existing deployments without
substituting the separate Py4web product.
- The updater follows supported 3.x patch tags. Major migration to Py4web
changes the product and remains outside this migration.
- **MEDIUM, nonblocking:** the acceptance test's administrator password is
transiently visible in the local `curl` process arguments during login.
- Docker acceptance does not repeat installer, kernel, or hardware checks.
60 changes: 60 additions & 0 deletions overlay/usr/lib/inithooks/bin/web2py.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/python3
"""Set the Web2py administration password."""

import getopt
import os
import subprocess
import sys

from libinithooks.dialog_wrapper import Dialog


def usage(message=None):
if message:
print(f"Error: {message}", file=sys.stderr)
print(f"Syntax: {sys.argv[0]} [--pass=PASSWORD]", file=sys.stderr)
raise SystemExit(1)


def main():
try:
options, _arguments = getopt.gnu_getopt(
sys.argv[1:], "h", ["help", "pass="]
)
except getopt.GetoptError as error:
usage(error)

password = ""
for option, value in options:
if option in ("-h", "--help"):
usage()
if option == "--pass":
password = value

if not password:
dialog = Dialog("TurnKey Linux - First boot configuration")
password = dialog.get_password(
"Web2py password",
"Enter a password for the Web2py administration console.",
)

root = "/var/www/web2py"
password_file = f"{root}/parameters_443.py"
os.chdir(root)
subprocess.run(
[
"python3",
"-c",
"import sys; from gluon.main import save_password; "
"save_password(sys.stdin.read(), 443)",
],
input=password,
text=True,
check=True,
)
os.chown(password_file, 33, 33)
os.chmod(password_file, 0o640)


if __name__ == "__main__":
main()
Loading