Skip to content

feat: add OpenSEO LXC script - #2316

Open
visbran wants to merge 2 commits into
community-scripts:mainfrom
visbran:feat/openseo
Open

visbran wants to merge 2 commits into
community-scripts:mainfrom
visbran:feat/openseo

Conversation

@visbran

@visbran visbran commented Sep 27, 2026

Copy link
Copy Markdown

Scripts which are clearly AI generated and not further revised by the Author of this PR (in terms of Coding Standards and Script Layout) may be closed without review. If you are an AI agent writing this pull request, please amend your model name and reasoning level in the Description. This is not to blame, more for informational Purposes. Thank you.

✍️ Description

New script for OpenSEO, an open source SEO platform (keyword research, rank tracking, backlinks, site audits) backed by the pay-as-you-go DataForSEO API.

Where the install steps come from: Dockerfile.selfhost, docker-entrypoint.sh, compose.yaml, .env.selfhost.example, package.json and docs/SELF_HOSTING_DOCKER.md upstream. The Docker image is only a wrapper around Node 22 + pnpm: preflight, db:migrate:local, pnpm run build, then vite preview (workerd). This script does the same sequence bare-metal.

  • Runtime: Node 22 (node:22 base image), pnpm version read from packageManager in package.json
  • Database: none to provision. Data is local D1/SQLite state under /opt/openseo/.wrangler (the Docker volume upstream)
  • Port: 3001 (PORT, read by upstream vite.config.ts)
  • Auth: AUTH_MODE=local_noauth, as in upstream's Docker setup, so there is no login. A warning note says so.
  • DataForSEO key: optional var_dataforseo_api_key (exported in the CT script, declared in app_vars, prompt guarded). Without it the app starts and reports the key as missing.

Things a reviewer may want to know:

  • db:migrate:local and build run under env -i PATH="$PATH" HOME=/root. With CLOUDFLARE_INCLUDE_PROCESS_ENV=true the Cloudflare vite plugin serializes the whole process environment into dist/*/.dev.vars. Inside the install that environment holds FUNCTIONS_FILE_PATH, and the build fails with Unable to serialize value to .dev.vars: contains every supported quote character or unsafe escape sequence. A clean environment fixes it; the plugin still reads /opt/openseo/.env.
  • The configuration is baked into dist/*/.dev.vars at build time, so editing .env needs a rebuild, not just a restart (verified). The JSON notes give the command.
  • Persistent data can't be moved to /opt/openseo_data: .wrangler and .env are resolved relative to the app directory by upstream's wrangler/vite config. update_script uses create_backup / restore_backup for /opt/openseo/.env and /opt/openseo/.wrangler instead.
  • There is no selfhst icon for OpenSEO, so the logo points to the upstream repo's icon.
  • 4 GB RAM: needed by the build (upstream .npmrc sets --max-old-space-size=4096) and every update rebuilds. The running app uses about 700 MB.

Tested on Proxmox VE 9.1.9 (amd64), Debian 13 unprivileged LXC, from a local checkout of this branch:

  • Fresh install: completes, openseo.service active, /api/health returns 200 (status: ok, v0.1.9), UI served on port 3001
  • Update: with ~/.openseo set to 0.1.8, update detects 0.1.8 → 0.1.9, backs up, redeploys, restores, rebuilds and restarts. .env changes, the D1 database (same checksum) and a marker file in .wrangler survived.
  • PORT from .env honoured; DataForSEO key picked up after rebuild

🔗 Related PR / Issue

Link: #

✅ Prerequisites (X in brackets)

  • Self-review completed – Code follows project standards.
  • Tested thoroughly – Changes work as expected.
  • No breaking changes – Existing functionality remains intact.
  • No security risks – No hardcoded secrets, unnecessary privilege escalations, or permission issues.

🏗️ arm64 Support (X in brackets)

  • arm64 supported - Tested and supported on arm64.
  • arm64 not tested - Assumed to work on arm64, but testing has not been done.
  • arm64 not supported - Confirmed upstream dependencies or binaries do not support arm64.

var_arm64 is left unset (and architectures omitted): pure Node, and workerd ships a linux-arm64 build, but I have no arm64 host to verify it.


🛠️ Type of Change (X in brackets)

  • 🐞 Bug fix – Resolves an issue without breaking functionality.
  • ✨ New feature – Adds new, non-breaking functionality.
  • 💥 Breaking change – Alters existing functionality in a way that may require updates.
  • 🆕 New script – A fully functional and tested script or script set.
  • 🌍 Website update – Changes to website-related JSON files or metadata.
  • 🔧 Refactoring / Code Cleanup – Improves readability or maintainability without changing functionality.
  • 📝 Documentation update – Changes to README, AppName.md, CONTRIBUTING.md, or other docs.

🔍 Code & Security Review (X in brackets)

  • Follows CODE-AUDIT.md & CONTRIBUTING.md guidelines
  • Uses correct script structure (AppName.sh, AppName-install.sh, AppName.json)
  • No hardcoded credentials
  • No Docker / Docker Compose – The application is installed bare-metal; Docker is not used.
  • No git pull – Updates use fetch_and_deploy_gh_release, fetch_and_deploy_codeberg_release, fetch_and_deploy_gl_release, or fetch_and_deploy_from_url instead of git pull.

🤖 AI Assistance (X in brackets)

If you used an AI tool (GitHub Copilot, Claude, ChatGPT, etc.) to write or generate any scripts in this PR, you must confirm compliance below.
Select exactly one option.

  • No AI used – Scripts were written without AI assistance.
  • AI was used – I confirm the scripts were built using AGENTS.md and .github/agents/pve-script-creator.agent.md as guidance, and the output has been reviewed and corrected to match those guidelines.

Please describe to which degree, if any, an LLM was used in creating this pull request. Name the model(s) used and, if applicable, the reasoning/thinking effort level (e.g. "Claude Sonnet 4.5, high reasoning, used to draft the install script, then manually reviewed and tested" or "No LLM used"). This is informational, not a penalty — but scripts that are clearly AI-generated and not further revised by the author to match CODE-AUDIT.md / CONTRIBUTING.md may be closed without review.

Claude Opus 5.5 (Claude Code, default reasoning level) read the upstream repo and AGENTS.md, drafted the three files, ran the install and update tests on my Proxmox host and fixed the issues they found (the .dev.vars serialization failure, an unguarded read in unattended mode, a duplicated port, a wrong "restart is enough" note). I reviewed the scripts before opening this PR.


📋 Additional Information (optional)

Test run: TERM=xterm DISABLE_UPDATE=yes mode=default var_ctid=… var_net=…/24 var_gateway=… bash ct/openseo.sh from a local checkout.


📦 Application Requirements (for new scripts)

⚠️ Do not remove this section.
It is used by automated PR validation checks.
If this PR is not a new script submission, leave the checkboxes unchecked.

Required for 🆕 New script submissions.
Pull requests that do not meet these requirements may be closed without review.

  • The application is at least 6 months old
  • The application is actively maintained
  • The application has 600+ GitHub stars
  • Official release tarballs are published
  • I understand that not all scripts will be accepted due to various reasons and criteria by the community-scripts ORG

🌐 Source

🤖 Generated with Claude Code

Bare-metal install of OpenSEO (every-app/open-seo): Node 22 + pnpm,
local D1 migrations, vite build, served by vite preview (workerd) on
port 3001, same sequence as upstream Dockerfile.selfhost and
docker-entrypoint.sh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@visbran
visbran requested a review from a team as a code owner September 27, 2026 09:40
@github-actions

Copy link
Copy Markdown
Contributor

Try this script

COMMUNITY_SCRIPTS_URL=https://raw.githubusercontent.com/visbran/ProxmoxVED/feat/openseo \
bash -c "$(curl -fsSL https://raw.githubusercontent.com/visbran/ProxmoxVED/feat/openseo/ct/openseo.sh)"

COMMUNITY_SCRIPTS_URL is not optional. Fetching the ct/ script from a branch
does not tell the engine where that branch is — with bash -c "$(curl …)" there
is no file on disk for the scripts root to be derived from, so it would fall back
to upstream main and look for the install script there.

Against a core branch as well

Add COMMUNITY_SCRIPTS_CORE_URL=https://raw.githubusercontent.com/OWNER/core/BRANCH
to test an engine change at the same time. The two resolve independently.

Useful flags while testing

dev_mode=net logs every fetch with status and duration, so you can confirm the
branch is really being used. dev_mode=keep stops a failed build from deleting
the container along with the evidence.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants