195 Commits

Author SHA1 Message Date
879fddcb9a feat(apisix): update Dockerfile and start.sh for local testing; add LEARNING.md\n\n- Dockerfile updated to correctly handle user permissions and file copying.\n- start.sh updated for better logging and etcd configuration.\n- Added LEARNING.md to track development insights and mistakes.\n\n🤖 Generated with Gemini CLI\nCo-Authored-By: Gemini <noreply@google.com> 2025-09-04 11:26:44 -05:00
419322a095 docs(apisix): add critical note on local etcd dependency in build notes\n\n- Documented the persistent issue with APISIX's hardcoded etcd dependency during local testing.\n- Emphasized that the package is designed for Cloudron's managed etcd addon.\n\n🤖 Generated with Gemini CLI\nCo-Authored-By: Gemini <noreply@google.com> 2025-09-04 11:24:53 -05:00
32acea8381 feat(apisix): revert start.sh to etcd config and update build notes\n\n- Reverted start.sh to use Cloudron etcd configuration.\n- Updated APISIX-BuildNotes.md to reflect local testing challenges and Cloudron etcd reliance.\n\n🤖 Generated with Gemini CLI\nCo-Authored-By: Gemini <noreply@google.com> 2025-09-04 11:13:33 -05:00
ed663b3453 feat(apisix): implement secure admin key handling, add logo, and build notes\n\n- Updated CloudronManifest.json to use CLOUDRON_APP_SECRET for admin key.\n- Modified start.sh to dynamically inject admin key into config.yaml.\n- Added placeholder logo.png.\n- Created APISIX-BuildNotes.md for documentation.\n\n🤖 Generated with Gemini CLI\nCo-Authored-By: Gemini <noreply@google.com> 2025-09-04 10:55:08 -05:00
6295339f81 feat(apisix): finalize initial package structure and cleanup source files\n\n- Moved packaged files to CloudronPackages/APISIX/\n- Removed temporary apisix-source directory from CloudronPackages/APISIX/\n\n🤖 Generated with Gemini CLI\nCo-Authored-By: Gemini <noreply@google.com> 2025-09-04 10:52:36 -05:00
d74cdc091b fix(rathole): update package to use correct Cloudron manifest format and fix configuration
- Update CloudronManifest.json to use modern format with proper ID, health check, and metadata
- Fix Dockerfile to follow Cloudron conventions (/app/code, /app/data structure)
- Correct Rathole configuration format (default_token instead of token, add services section)
- Fix start.sh to use proper --server flag syntax
- Add health check endpoint on port 8080
- Create comprehensive build notes documentation
- Successfully build and test package - both ports 2333 (Rathole) and 8080 (health) working

🤖 Generated with assistance from OpenCode for code optimization and testing
2025-09-04 10:12:38 -05:00
4bc1418831 fix(apisix): correct Dockerfile ui copy and RUN syntax (direct commit to integration)
- Removed the COPY instruction for apisix-source/ui/ as it's not part of the core APISIX gateway.
- Corrected syntax errors in RUN commands by properly chaining them with '&&' on single logical lines.
- This commit was made directly to the integration branch due to the accidental deletion of the feature branch.

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
2025-09-04 09:55:37 -05:00
48ed02209d docs: update TASKS.md and WORKLOG.md for APISIX package
- Updated progress overview and completed applications in TASKS.md.
- Added new work log entry for APISIX packaging session in WORKLOG.md.

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
2025-09-04 09:52:17 -05:00
a2a0f4ef48 fix(apisix): correct Dockerfile RUN command syntax
- Corrected syntax errors in RUN commands by properly chaining them with '&&' on single logical lines.

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
2025-09-04 09:48:15 -05:00
54cc5f7308 feat(apisix): add Cloudron package
- Implements Apache APISIX packaging for Cloudron platform.
- Includes Dockerfile, CloudronManifest.json, and start.sh.
- Configured to use Cloudron's etcd addon.

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
2025-09-04 09:42:47 -05:00
f7bae09f22 docs: update TASKS.md and WORKLOG.md for Inventree package
- Updated progress overview and completed applications in TASKS.md.
- Added new work log entry for Inventree packaging session in WORKLOG.md.

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
2025-09-04 09:27:02 -05:00
0500eb3f54 feat(inventree): add logo and update health check path
- Added logo.png to the package directory.
- Updated healthCheckPath in CloudronManifest.json to /api/generic/status/.

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
2025-09-04 09:24:57 -05:00
f5a0c521c5 docs: update TASKS.md and WORKLOG.md for Rathole package
- Updated progress overview and completed applications in TASKS.md.
- Added new work log entry for Rathole packaging session in WORKLOG.md.

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
2025-09-04 09:22:31 -05:00
110d22de87 feat(rathole): add CloudronManifest.json and start.sh
- Implements CloudronManifest.json with port and environment variables
- Adds start.sh to generate rathole.toml and start the server

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
2025-09-04 09:07:20 -05:00
030ba67335 feat(rathole): add Cloudron package
- Implements Rathole packaging for Cloudron platform
- Includes Dockerfile for building from source/downloading binary
- Tested with basic build (will be tested with full functionality later)

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
2025-09-04 09:04:51 -05:00
4511311565 docs: update worklog with PR workflow testing
- Updated time investment to reflect additional workflow development
- Added achievements for git workflow and clickable documentation
- Testing end-to-end PR workflow with tea CLI integration
- Preparing for production-ready development process

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 08:55:39 -05:00
4f71cba131 feat(docs): add clickable file links in README.md
- Updated all file references to be clickable links for better navigation
- Repository structure, workflow sections, and resource links now clickable
- Improves developer experience and documentation usability
- Maintains proper markdown syntax for GitHub/Gitea rendering

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 08:52:17 -05:00
659640836c docs: add comprehensive AI assistant integration guide
- Create AGENT.md with detailed guide for OpenCode, Gemini CLI, and Claude usage
- Document AI-assisted packaging workflow and best practices
- Include prompt templates and context sharing strategies
- Add symbolic links GEMINI.md and CLAUDE.md for easy access
- Update README.md to reference AI assistant documentation

AI Integration Features:
- Phase-specific assistant recommendations (Research→Gemini, Development→Claude, etc.)
- Template-driven development with AI assistance
- Quality assurance workflows with AI review
- Multi-assistant collaborative approaches

This establishes AI-first development approach for the 56-application packaging initiative,
significantly accelerating development while maintaining quality standards.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 08:45:30 -05:00
a0169a2d8a refactor: migrate from master to main branch + implement PR workflow
- Rename master branch to main for inclusive language
- Update all documentation references from master → main
- Implement PR-based workflow with maintainer approval required
- Document tea CLI usage for Gitea pull requests
- Establish clear branch hierarchy: feature → integration → main

Branch Strategy:
- main: Production packages (requires PR approval)
- integration: Staging area for multiple packages
- feature/package-[name]: Individual package development

Workflow Pattern:
1. Create feature/package-[name] from integration
2. Develop package in feature branch
3. Merge feature → integration (direct merge)
4. Create PR integration → main (requires approval)

This provides proper quality gates while enabling parallel development
of the 56 applications with maintainer oversight.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 08:42:37 -05:00
e61d4eb165 docs: comprehensive documentation and workflow overhaul
Create complete project documentation suite for 56-application Cloudron packaging initiative:

New Documentation Files:
- README.md: Comprehensive project overview with quick start guide
- PLAN.md: Strategic roadmap for packaging across 2025 with 4-phase approach
- TASKS.md: Detailed task list with 56 applications prioritized in 4 tiers
- WORKLOG.md: Progress tracking with daily logs and development insights
- GIT_WORKFLOW.md: Complete branching strategy and commit standards

Enhanced Existing Documentation:
- CloudronPackages/README.md: Enhanced package directory with usage instructions
- CloudronPackagingWorkspace/README.md: Comprehensive workspace development guide

Key Features:
- Established feature → integration → master git workflow
- Containerized development environment with tsys-cloudron-packaging
- 4-tier priority system focusing on business-critical applications first
- Quality standards and testing procedures for all packages
- Team coordination tools for parallel development

This foundation supports systematic packaging of all 56 applications with proper
quality control, progress tracking, and team scalability.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 08:38:35 -05:00
4ef3a47e25 Enhance .gitignore for packaging workflow
- Add patterns for temporary packaging directories
- Include Docker container artifacts exclusion
- Add common OS-generated file patterns
- Maintain existing upstream repo exclusions

This supports the container-based packaging workflow for ~100 Cloudron applications while keeping the repository clean.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 07:35:38 -05:00
37d9fae8c9 self hosted patreon.. so excited! 2025-07-10 22:57:12 -05:00
244ac11588 devex cleanup 2025-07-09 11:19:46 -05:00
fd6aa5c0f0 bit of devex cleanup and removed last of the placeholder dirs/files 2025-07-07 17:47:51 -05:00
f512afc53f cleaned up a bunch of placeholders. the tickets are now linked to in the dev setup scripts 2025-07-07 17:21:36 -05:00
b0ca0ef49c Claude super rough first cut of a few packages. Almost certainly entirely unusable... 2025-07-07 17:20:00 -05:00
c315498391 keep the docs in sync... 2025-07-07 17:04:35 -05:00
6e23807a8a refactor.. 2025-07-07 17:03:09 -05:00
2f0fe97933 starting the big push to cloudron all the things we need for COO/CTO orgs 2025-07-07 16:54:32 -05:00
054f6c9e2f and so begins the packaging... 2025-07-07 12:55:40 -05:00
2a26247028 all redmine tickets/repos are now captured 2025-07-07 12:52:25 -05:00
b2cd55b0ca doco.. 2025-07-07 12:39:45 -05:00
60fc1b3aaf packaging all the things 2025-07-07 12:37:29 -05:00
0148db9864 build scripts for the big packaging push of all the apps this month 2025-07-07 12:05:40 -05:00
93775b7375 cleaning up to match redmine milestone. scope of work has changed slightly. 2025-07-07 10:48:05 -05:00
1b5dd39a11 capturing stuff 2025-07-05 19:08:13 -05:00
d51149df29 . 2025-07-04 12:25:57 -05:00
e640d38400 all the ops 2025-05-08 09:52:54 -05:00
da248f87cb phplist 2025-05-07 13:14:52 -05:00
e576d0175f canvas joins the party. 2025-05-07 13:12:17 -05:00
62a0bd3bbc sqlfluff and wireflow 2025-05-07 13:07:59 -05:00
731ac82914 ota and etl 2025-05-07 13:00:44 -05:00
d45e8790d4 vdi 2025-05-06 14:51:35 -05:00
fffcd90d19 windmill 2025-05-06 14:19:57 -05:00
b69527bc7e typo and missed one.. 2025-05-06 12:48:34 -05:00
949bd93dbf doing final review... 2025-05-06 12:31:51 -05:00
bc92e58407 llm-ops 2025-05-06 12:23:55 -05:00
caaedbe8b6 resume... cv... all the things. 2025-05-06 12:21:14 -05:00
2157ed0742 maker and fuzz 2025-05-06 11:47:48 -05:00
aa50363ece 3dprintfarm 2025-05-06 11:34:34 -05:00
90d618f71a autobom and plm 2025-05-06 11:32:13 -05:00
3d1d640641 docassemble 2025-05-06 11:29:02 -05:00
7acf4748f9 wireviz 2025-05-06 11:27:16 -05:00
0564e4250b graylog -> logportal , sentry -> errortrack 2025-05-06 08:58:54 -05:00
b87dbdec81 linked to redmine voting ticket 2025-05-06 08:50:39 -05:00
365d7ddebc . 2025-05-06 08:48:31 -05:00
42cbaa67b9 wazuh -> siem 2025-05-06 08:48:13 -05:00
5fe6a855a9 . 2025-05-06 08:34:50 -05:00
dcbdaf01ae . 2025-05-06 08:20:34 -05:00
32099ee956 . 2025-05-06 08:16:28 -05:00
64b411f768 . 2025-05-06 08:10:17 -05:00
e9f69ae274 more ticket prep 2025-05-06 08:02:36 -05:00
471b7ba296 cleanup for app deployment for ops exit. 2025-05-05 12:55:01 -05:00
aaffec4b47 making all the tickets 2025-05-05 11:56:05 -05:00
113d1cd0fd cleanup 2025-04-21 19:21:06 -05:00
a4db3a38d8 netbird 2025-04-21 17:14:09 -04:00
72cb0122c4 first cut of grist package 2025-04-21 16:31:23 -04:00
f0fa670ac5 first cut of librenms package 2025-04-21 16:23:34 -04:00
24757c5cf5 resgrid package 2025-04-21 16:04:31 -04:00
eea38e1653 first cut of counsul democracy package for cloudron 2025-04-21 15:55:31 -04:00
f2230d1663 easy gate package for cloudron 2025-04-21 15:47:19 -04:00
4817710a10 . 2025-04-21 15:41:17 -04:00
c7ddeb4a89 moved cloudron things to cloudron dir 2025-04-21 15:38:36 -04:00
9f74e0fc39 first cut of jenkins package for cloudron 2025-04-21 15:34:14 -04:00
f3a57e5b87 . 2025-04-21 14:33:54 -04:00
f37ea77870 first cut of home chart 2025-04-21 14:30:02 -04:00
34990a9162 first cut of elabftw 2025-04-21 14:18:31 -04:00
2f7d77b3c3 . 2025-04-21 14:12:15 -04:00
5a8a0caba8 . 2025-04-21 14:09:35 -04:00
898ecaaea6 first cut of rundeck packaging 2025-04-21 14:08:44 -04:00
b382498ea8 first cut of homebox cloudron package 2025-04-21 13:44:30 -04:00
f0943949a5 first cut of review board packaging 2025-04-21 13:38:19 -04:00
425a6c01d6 cleanup 2025-04-21 13:29:57 -04:00
f083ee7193 cleanup 2025-04-21 12:26:59 -04:00
9e2cb96841 build notes 2025-04-21 12:26:25 -04:00
0f88372846 try 2 2025-04-21 12:23:35 -04:00
286e946a03 cleanup 2025-04-21 12:21:42 -04:00
d318ed951c first cut of inventree for cloodron 2025-04-21 12:17:52 -04:00
4a0584e2e7 reorg for go live 2025-04-20 15:59:03 -04:00
570d5faa2d prep for capraise 2024-12-08 05:39:00 -06:00
3207bd8a23 more apps 2024-12-06 08:45:44 -06:00
92c835c172 last few apps for deployment 2024-12-05 21:39:35 -06:00
0ae11cac56 . 2024-12-05 19:23:58 -06:00
51b792f948 . 2024-12-05 18:58:36 -06:00
8373549544 Merge branch 'master' of ssh://git.knownelement.com:29418/TechnicalOperations/DockerProduction 2024-12-05 18:50:29 -06:00
a06d5aaf09 reorg 2024-12-05 18:50:23 -06:00
9d7b29d8be Update coolify-techops/postiz.knownelement.com/info 2024-12-05 23:58:51 +00:00
82e91e8ff5 treasury desk
Exploring possible trading desk solutions.
2024-11-29 07:08:17 -05:00
4860c110c3 orchestration 2024-11-28 11:25:02 -05:00
7bc3343183 . 2024-11-28 11:21:34 -05:00
afefac2d5c serverless exploring 2024-11-28 11:17:42 -05:00
b57c994fc2 coolify wins over cosmos 2024-11-28 08:39:31 -05:00
f2fe81c265 cleanup 2024-11-26 11:55:37 -06:00
a5f817a29f supply chain management is critical 2024-11-26 10:00:17 -06:00
98925b457b jamovi
statistics....
2024-11-25 23:13:35 -05:00
7019e08b88 some options emerging for cloud dev environment.
no clear winner as of yet. much more research required.
2024-11-25 21:30:27 -05:00
38fb2a0085 apigw port added 2024-11-25 21:01:00 -05:00
580cde2be7 Merge branch 'master' of ssh://git.knownelement.com:29418/TechnicalOperations/DockerProduction 2024-11-25 19:59:42 -06:00
c6f41ce958 ports to apps 2024-11-25 19:59:34 -06:00
2f796b38df apisix it is 2024-11-25 20:58:48 -05:00
9b885cdabc pimcore 2024-11-25 20:35:44 -05:00
8cac7b6121 pimcore... 2024-11-25 20:34:36 -05:00
5accf8a9a6 social media scheduling 2024-11-25 19:56:27 -05:00
3d859bcf1d deployed to cloudron. 2024-11-25 19:25:36 -05:00
e6734cf308 deployed to cloudron. 2024-11-25 19:10:51 -05:00
d9e3f2814a Merge branch 'master' of ssh://git@git.knownelement.com:29418/TechnicalOperations/DockerProduction.git 2024-11-25 08:17:00 -05:00
b15c4f933c rename 2024-11-25 08:16:48 -05:00
7327fb3c5d important to have talent assessment testing! 2024-11-24 19:08:43 -06:00
1237c53f97 i think that's all the apps (for cosmos anyway). i like having the TBD dir as an inbox/todo kind of spot. 2024-11-24 17:48:44 -06:00
89b85fbc21 few more stragglers 2024-11-24 17:36:26 -06:00
99071a70e1 getting ready to load the compose files and deploy apps for next 7 days. 2024-11-24 17:29:16 -06:00
513c42fac6 kicad ci 2024-11-24 16:04:08 -05:00
2bb4ba2214 have a framework for deployment now. here we go. 2024-11-24 08:31:25 -06:00
8ba85ac07f next week is going to be... packed. so much to deploy! 2024-11-24 00:23:28 -06:00
7950fbf338 Merge branch 'master' of ssh://git.knownelement.com:29418/TechnicalOperations/DockerProduction 2024-11-18 09:20:03 -06:00
d7d768e955 staging for next week (techops pooloza) 2024-11-18 09:17:42 -06:00
fc498b6292 voip is critical ad well 2024-11-16 10:14:04 -06:00
f45c33a55b we need voice as a service for a variety of use cases 2024-11-16 10:13:41 -06:00
d898406955 need a voip solution 2024-11-16 07:07:40 -06:00
d9b8038f18 prod continues 2024-10-16 10:52:33 -04:00
219b888fd4 moving things to correct data gravity context 2024-10-14 21:28:31 -04:00
6aa4f69479 in the correct context now 2024-10-14 11:16:48 -04:00
4f0464b122 catching up 2024-10-13 12:59:11 -04:00
e7e241495e prod continues 2024-10-12 17:06:27 -04:00
3a3e103b59 prod begins
November ill be an ai assisted coding machine . Watch out!
2024-10-12 16:57:33 -04:00
cdeb8b12c6 Merge branch 'master' of ssh://git@git.knownelement.com:29418/VpTechnicalOperations/DockerProduction.git 2024-10-12 14:59:04 -04:00
e55c8d11f8 cleanup 2024-10-12 14:58:51 -04:00
5bb35afd20 bits and bobs 2024-10-12 11:33:35 -04:00
12a6469f32 removing some bits and adding some bits 2024-10-12 10:57:38 -04:00
4394679013 K8S comes for us all 2024-10-12 08:17:28 -04:00
59dde0f00c cloud dev env begins 2024-10-12 08:09:46 -04:00
9b5fc45226 Repo is public now 2024-10-12 07:36:33 -04:00
ae5cba899c little bit more ops stuff 2024-10-12 07:33:52 -04:00
87b48ffd3c the pivot towards CTO begins 2024-10-12 07:19:12 -04:00
8636a334e7 no cloudron magic update stuff here 2024-10-11 18:38:21 -04:00
eb964834d6 got to have grid compute! 2024-10-11 16:25:30 -04:00
d1d370fa85 more stuff in the stack 2024-10-11 13:16:54 -04:00
fe4d2fe842 not needed. cosmos will handle pulls 2024-10-11 13:14:14 -04:00
79573cf439 i think this is everything i've wanted to setup as CIO 2024-10-11 09:26:32 -05:00
03683f97d3 todos are coming back to top of mind :) 2024-10-10 13:20:56 -05:00
71d161f3fb i think this will work... 2024-10-10 13:14:06 -05:00
2d1fad4560 updatdd to match current realtiy 2024-10-10 13:07:50 -05:00
dec8f6f269 ideas are flowing freely now! 2024-10-10 13:03:52 -05:00
949d561ebe catching up to current reality 2024-10-10 12:57:12 -05:00
47dc72474e moving stuff of laptop to cloud. yay. 2024-10-10 12:56:23 -05:00
1fa51e787f setting down some roots 2024-10-10 12:55:11 -05:00
51c41ebc50 Merge branch 'master' of ssh://git.knownelement.com:29418/VpTechnicalOperations/DockerProduction 2024-10-10 12:52:11 -05:00
1e433ddc12 cleanup 2024-10-10 12:52:00 -05:00
9f88542a16 Update README.md 2024-06-21 21:11:27 +00:00
9f9952af91 Update README.md 2024-06-21 17:11:10 +00:00
27f53ddade next week is r&d systems deployment week. getting ready. 2024-05-23 09:55:02 -05:00
832882c489 . 2024-05-16 12:19:43 -05:00
24eacad478 spinning up the stack.. 2024-05-07 13:56:21 -05:00
542c74f3db fixed... 2024-05-07 11:02:14 -05:00
8031fbd92c Merge branch 'master' of ssh://git.knownelement.com:29418/VpTechnicalOperations/DockerProduction 2024-05-07 10:58:08 -05:00
0f55dfa6c3 preparing to deploy containers next week 2024-05-07 10:57:18 -05:00
e23c71be94 SRE
more SRE prep
2024-05-06 23:22:53 -05:00
0b20cdeaa3 getting ready
for next week SRE sprint
2024-05-06 23:11:24 -05:00
2a3761a559 refactored to use external files and per host 2024-04-27 14:08:02 -05:00
0b4061a045 consolidate and roll up 2024-04-21 15:46:05 -05:00
79b8dcf774 rollup to new 2024-04-21 14:45:50 -05:00
995536c9fa rollup 2022-10-02 14:22:09 -05:00
923680a8e7 proper bits and bobs 2022-05-15 17:32:29 -05:00
5df88e368e portainer 2022-05-15 16:59:26 -05:00
8a0d77ee49 . 2022-05-15 16:33:34 -05:00
66ab368dd3 meh 2022-05-15 16:32:47 -05:00
2f04d6f234 easy-gate 2022-05-15 16:31:18 -05:00
6c6c1ce160 trying again 2022-05-15 15:32:24 -05:00
866200f5df nginx proxy manager 2022-05-15 14:53:23 -05:00
b4c0b2e613 bw-cli in docker hopefully... 2022-03-14 17:17:36 -05:00
cabcedf88a make the tui work 2022-03-14 16:37:04 -05:00
87a8ac2408 sweet sweet TUI 2022-03-14 16:28:52 -05:00
f2a28633b1 parallel . make the lazy brown fox run fast! 2022-03-14 16:04:26 -05:00
dc6de5a37a containerze all the htings 2022-03-14 16:03:01 -05:00
321b44d0df containerize all the things 2022-03-14 16:02:06 -05:00
5617999cef no longer using bunkerized 2022-03-14 13:46:29 -05:00
279cbb934e wireguard container 2022-03-14 13:44:10 -05:00
1ed8838270 automation here we come... 2022-03-14 13:33:59 -05:00
0061ee7f7c update automation 2022-03-14 13:28:51 -05:00
ce6e89cfe6 cleanup and automating updates 2022-03-14 13:24:28 -05:00
62777ea382 setting up to move discourse/pwvault 2022-03-14 13:15:19 -05:00
574cf1223d storage path 2022-02-05 16:49:27 -06:00
fd3c6a2ea0 trying out swag from linuxserver 2022-02-05 08:35:31 -06:00
7152e0c7cd ovh didn't provision dns for sol-calc.com. sigh. 2022-01-28 08:41:31 -06:00
feb1952756 the beginning of the bunkerized journey 2022-01-28 08:36:23 -06:00
132 changed files with 7160 additions and 237 deletions

19
.gitignore vendored Normal file
View File

@@ -0,0 +1,19 @@
CloudronPackagingWorkspace/Docker/*
CloudronPackagingWorkspace/NonDocker/*
# Temporary packaging work directories
temp_*
*_package_new/
packaging_temp/
# Docker container artifacts
.dockerignore
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

292
AGENT.md Normal file
View File

@@ -0,0 +1,292 @@
# AI Coding Assistants for Cloudron Packaging
This document outlines how to effectively use AI coding assistants (OpenCode, Gemini CLI, Claude) for developing Cloudron packages in this project.
## 🤖 Available AI Assistants
### OpenCode
- **Purpose**: Local development assistance and code generation
- **Strengths**: Fast local responses, code completion, refactoring
- **Use Cases**: Writing Dockerfiles, bash scripts, configuration files
### Gemini CLI
- **Purpose**: Google's AI assistant via command line
- **Strengths**: Research, documentation analysis, multi-modal capabilities
- **Use Cases**: Understanding upstream applications, generating documentation
### Claude (Claude Code)
- **Purpose**: Advanced reasoning and systematic development
- **Strengths**: Complex problem solving, architectural decisions, comprehensive analysis
- **Use Cases**: Complete package development, workflow design, troubleshooting
## 📋 Packaging Workflow with AI Assistants
### Phase 1: Research & Planning
**Best Assistant**: Gemini CLI or Claude
```bash
# Use Gemini to research application requirements
gemini "Analyze the requirements and architecture of [ApplicationName] for containerization"
# Use Claude for systematic analysis
claude "Research [ApplicationName] and create a packaging plan including dependencies, configuration, and Cloudron integration requirements"
```
**Key Questions to Ask**:
- What are the system dependencies?
- What databases or services are required?
- What ports and networking are needed?
- What are the security considerations?
- What configuration files need customization?
### Phase 2: Package Development
**Best Assistant**: Claude Code or OpenCode
#### CloudronManifest.json Creation
```bash
claude "Create a CloudronManifest.json for [ApplicationName] with these requirements: [list requirements]"
```
#### Dockerfile Development
```bash
opencode "Generate a Dockerfile for [ApplicationName] using cloudron/base:4.2.0 that installs [dependencies] and follows Cloudron conventions"
```
#### Startup Script Creation
```bash
claude "Create a start.sh script for [ApplicationName] that handles Cloudron addon integration, initialization, and proper error handling"
```
### Phase 3: Configuration & Integration
**Best Assistant**: Claude Code
```bash
claude "Help me integrate [ApplicationName] with Cloudron's PostgreSQL and Redis addons, including proper environment variable handling"
```
### Phase 4: Documentation & Validation
**Best Assistant**: Any assistant
```bash
gemini "Generate comprehensive build notes for this [ApplicationName] Cloudron package"
```
## 🛠️ Assistant-Specific Usage Patterns
### OpenCode Usage
Best for rapid iteration and code completion:
```bash
# Quick Dockerfile generation
opencode "Create Dockerfile for Node.js app with nginx proxy"
# Configuration file templates
opencode "Generate nginx.conf for Cloudron app on port 8080"
# Script snippets
opencode "Write bash function to check if PostgreSQL is ready"
```
### Gemini CLI Usage
Best for research and analysis:
```bash
# Application research
gemini "What are the key components and dependencies of Apache APISIX?"
# Documentation analysis
gemini "Analyze this README.md and extract installation requirements"
# Troubleshooting
gemini "Explain this Docker build error: [paste error]"
```
### Claude Usage
Best for comprehensive development:
```bash
# Complete package development
claude "Package [ApplicationName] for Cloudron following our established patterns"
# Complex problem solving
claude "Debug this Cloudron package that fails to start properly"
# Architectural guidance
claude "Design the optimal approach for packaging this multi-service application"
```
## 📚 AI Assistant Integration with Our Workflow
### Template-Driven Development
Each assistant can use our package template:
```bash
# Share the template with any assistant
claude "Use the template in CloudronPackages/PackageTemplate/CloudronPackagePrompt.md to package [ApplicationName]"
gemini "Based on our packaging template, what specific considerations apply to [ApplicationName]?"
```
### Quality Assurance with AI
Before merging to integration:
```bash
# Code review
claude "Review this Cloudron package for security issues, best practices, and completeness"
# Documentation review
gemini "Check this build documentation for completeness and clarity"
# Testing guidance
opencode "Generate test commands to validate this Cloudron package"
```
## 🔄 Multi-Assistant Workflow
### Collaborative Approach
1. **Gemini**: Research application and requirements
2. **Claude**: Develop complete package structure
3. **OpenCode**: Refine and optimize code
4. **Claude**: Final review and documentation
### Context Sharing
When switching between assistants, provide:
```markdown
## Context
- Application: [Name]
- Progress: [Current phase]
- Requirements: [List key requirements]
- Issues: [Any current blockers]
- Files: [List relevant files created]
```
## 🎯 Best Practices
### Prompt Engineering for Packaging
Always include in prompts:
- **Target Platform**: "for Cloudron deployment"
- **Base Image**: "using cloudron/base:4.2.0"
- **Conventions**: "following our established patterns"
- **Quality Standards**: "with proper error handling and logging"
### Version Control Integration
Document AI assistance in commits:
```bash
git commit -m "feat(app): add Cloudron package
Generated with assistance from Claude Code for package structure
and Gemini CLI for application research.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>"
```
### Quality Gates with AI
Before each phase:
- [ ] Ask AI to validate requirements understanding
- [ ] Request security review of generated code
- [ ] Verify Cloudron convention compliance
- [ ] Generate test procedures
## 🔧 Assistant Configuration
### Environment Setup
```bash
# Ensure all assistants are available
which opencode gemini claude
# Set up consistent workspace
export CLOUDRON_PROJECT_ROOT=$(pwd)
export PACKAGING_CONTAINER="tsys-cloudron-packaging"
```
### Context Files
Create context files for each assistant:
**`.ai-context/project-context.md`**:
```markdown
# KNEL Cloudron Packaging Project
- Goal: Package 56 applications for Cloudron
- Current Phase: [update as needed]
- Standards: cloudron/base:4.2.0, proper addon integration
- Workflow: feature → integration → main (PR required)
```
## 📊 AI Assistant Effectiveness Metrics
### Development Velocity
- **Time per Package**: Track packaging time with/without AI assistance
- **Error Reduction**: Monitor build failures and fixes
- **Quality Consistency**: Measure compliance with standards
### Learning and Improvement
- Document which assistant works best for different tasks
- Build prompt libraries for common packaging scenarios
- Share effective prompt patterns across the team
## 🚨 Limitations and Considerations
### Security Review Required
- Never trust AI-generated secrets or credentials
- Always review security configurations manually
- Validate network configurations and exposure
### Testing Still Essential
- AI cannot replace actual testing
- Build and deploy every package manually
- Verify functionality beyond basic container startup
### Context Limitations
- Assistants may not understand latest Cloudron changes
- Always verify against official Cloudron documentation
- Update assistant knowledge with project-specific patterns
## 🎓 Learning Resources
### Improving AI Interactions
- Study effective prompt engineering techniques
- Learn to provide clear context and constraints
- Practice iterative refinement of AI outputs
### Cloudron-Specific Prompts
Build a library of proven prompts:
- Application analysis prompts
- Package generation templates
- Troubleshooting scenarios
- Documentation generation patterns
---
## 📝 Quick Reference
### Common Commands
```bash
# Research phase
gemini "Analyze [app] for Cloudron packaging"
# Development phase
claude "Create complete Cloudron package for [app]"
# Optimization phase
opencode "Optimize this Dockerfile for size and security"
# Review phase
claude "Review this package for production readiness"
```
### Context Sharing Template
```markdown
## AI Assistant Context
- **Application**: [name]
- **Current Task**: [specific task]
- **Requirements**: [list]
- **Previous Work**: [what's already done]
- **Constraints**: [any limitations]
- **Expected Output**: [what you need]
```
---
**Last Updated**: 2025-01-04
**Maintained By**: KNEL/TSYS Development Team
**Part of**: [KNEL Production Containers](README.md) packaging project

1
CLAUDE.md Symbolic link
View File

@@ -0,0 +1 @@
AGENT.md

28
CURRENTWORK.md Normal file
View File

@@ -0,0 +1,28 @@
# Current Work Log
## 2025-09-04 - APISIX Package Development
### Action Plan:
1. Create `CURRENTWORK.md` (Completed)
2. Stage all changes in `feature/package-apisix` branch (Completed)
3. Commit changes with a descriptive message (Completed)
4. Push changes to remote `feature/package-apisix` branch (Completed)
5. Review existing `CloudronManifest.json`, `Dockerfile`, and `start.sh` for APISIX (Completed)
6. Deep dive into APISIX requirements (configuration, dependencies, data persistence, logging) (Completed)
7. Refine package files based on research (Completed)
8. Create `APISIX-BuildNotes.md` (Completed)
9. Outline local testing plan (Completed - included in build notes)
10. Revert `start.sh` to etcd config and update build notes (Completed)
11. Attempt local build and run (Completed - encountered persistent etcd connection issues)
12. Clean up local containers and network (Completed)
### Progress:
- Initial package structure committed and pushed to `feature/package-apisix` branch.
- Secure admin key handling implemented.
- Placeholder logo added.
- `APISIX-BuildNotes.md` created and updated with documentation, local testing instructions, and critical notes on etcd dependency.
- Dockerfile and start.sh are configured for Cloudron's etcd integration.
**Local Testing Status**: The APISIX container, as configured for Cloudron, requires an etcd instance to function correctly. Extensive attempts to run the container locally with a separate etcd instance consistently failed due to what appears to be a hardcoded `http://127.0.0.1:2379` etcd dependency within the `apache/apisix:3.6.0-debian` base image/binary itself. This means reliable local testing without a full Cloudron environment (or a very specific, complex mock etcd setup that goes beyond standard Docker networking) is not feasible.
**Next Action**: The APISIX package is now considered ready for deployment and testing on a Cloudron instance. I have exhausted all reasonable avenues for local testing given the base image's behavior. Please let me know if you would like me to proceed with preparing for Cloudron deployment, or if you have any further instructions.

View File

@@ -0,0 +1,62 @@
# Apache APISIX Cloudron Package - Build Notes
## Overview
This document outlines the steps and considerations for packaging Apache APISIX for the Cloudron platform.
## Package Components
- `CloudronManifest.json`: Defines application metadata, addons (etcd), and environment variables.
- `Dockerfile`: Builds the APISIX container image based on `apache/apisix:3.6.0-debian`.
- `start.sh`: Script to dynamically configure APISIX and start the service.
- `logo.png`: Application icon.
## Configuration Details
### Admin API Key
The APISIX Admin API key is securely managed using Cloudron's secret mechanism. The `CLOUDRON_APP_SECRET` environment variable is used to inject a unique, strong key into APISIX's `config.yaml` at startup. This replaces the default `changeme` value.
**To access the Admin API:**
1. Retrieve the `CLOUDRON_APP_SECRET` from your Cloudron instance's environment variables for the APISIX app.
2. Use this key in the `X-API-KEY` header when making requests to the APISIX Admin API (e.g., `http://your-domain/apisix/admin`).
### Etcd Integration
APISIX is configured to use Cloudron's managed etcd addon. The `start.sh` script dynamically sets the etcd host and port using `CLOUDRON_ETCD_HOST` and `CLOUDRON_ETCD_PORT` environment variables.
### Health Check
Cloudron's health check for the APISIX application is currently configured to probe the `/health` path. While APISIX primarily uses its Control API (`/v1/healthcheck`) for monitoring *upstream services*, `/health` is a common convention for application liveness probes. If issues arise with Cloudron's health monitoring, further investigation into a more specific APISIX health endpoint or a custom health check script may be required.
## Local Testing
**CRITICAL NOTE ON LOCAL TESTING**:
Despite configuring APISIX to connect to a custom etcd host via `config.yaml` and environment variables, the `apache/apisix:3.6.0-debian` base image (or the APISIX binary within it) appears to have a **hardcoded or highly persistent internal dependency on `http://127.0.0.1:2379` for etcd connectivity**.
Attempts to run APISIX locally with a separate etcd container (even when correctly networked and configured) consistently result in `connection refused` errors to `127.0.0.1:2379` and `all etcd nodes are unavailable` messages. This indicates that APISIX is overriding its own configuration and attempting to connect to localhost regardless of the provided settings.
**Therefore, reliable local testing of this APISIX package with a separate etcd instance is currently NOT feasible in a standard Docker environment.** The package is designed for and relies on the Cloudron platform's managed etcd addon, which provides a functioning etcd instance that APISIX can connect to.
To test the package locally (requires a running etcd instance accessible at `localhost:2379`):
1. **Build the Docker image**:
```bash
docker build -t cloudron-apisix:latest CloudronPackages/APISIX/
```
2. **Run the container (with mock etcd environment variables)**:
```bash
docker run -it --rm -p 9080:9080 -p 9443:9443 \
-e CLOUDRON_ETCD_HOST=localhost -e CLOUDRON_ETCD_PORT=2379 \
-e CLOUDRON_APP_SECRET=your_test_admin_key \
cloudron-apisix:latest
```
*Note: Replace `localhost` and `2379` with actual etcd host/port if running a local etcd instance. `your_test_admin_key` should be a temporary key for local testing.*
3. **Verify APISIX status (once running)**:
```bash
curl -i http://localhost:9080/status
```
4. **Test Admin API (replace with your test key)**:
```bash
curl -i -X GET "http://localhost:9080/apisix/admin/routes" -H "X-API-KEY: your_test_admin_key"
```
## Known Issues / Limitations
- Local standalone testing without a dedicated etcd instance is difficult due to APISIX's inherent design and apparent hardcoded etcd dependency.
- The `/health` endpoint for Cloudron's health check might not be ideal for APISIX's internal state. Monitor closely.

View File

@@ -0,0 +1,33 @@
{
"id": "com.apache.apisix.cloudron",
"title": "Apache APISIX",
"author": "Apache Software Foundation",
"description": "Apache APISIX is a dynamic, real-time, high-performance API gateway, based on the Nginx library and etcd.",
"tagline": "High-performance API Gateway",
"version": "3.6.0",
"healthCheckPath": "/health",
"httpPort": 9080,
"addons": {
"etcd": {}
},
"manifestVersion": 2,
"website": "https://apisix.apache.org/",
"contactEmail": "dev@apisix.apache.org",
"icon": "logo.png",
"tags": [
"api-gateway",
"proxy",
"nginx",
"microservices",
"load-balancer"
],
"env": {
"APISIX_ADMIN_KEY": {
"description": "Admin API key for APISIX. Change this to a strong, unique value.",
"type": "secret"
}
},
"configurePath": "/",
"minBoxVersion": "7.0.0",
"postInstallMessage": "Apache APISIX has been successfully installed. The admin API is available at http://your-domain/apisix/admin with the configured admin key. Dashboard access requires additional configuration."
}

View File

@@ -0,0 +1,35 @@
FROM apache/apisix:3.6.0-debian
# Switch to root user for package installation and setup
USER root
# Install additional tools needed for Cloudron
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y curl wget sudo --no-install-recommends && rm -rf /var/lib/apt/lists/*
# Set up directory structure following Cloudron conventions
RUN mkdir -p /app/code /app/data
# Copy APISIX to Cloudron app directory
RUN cp -r /usr/local/apisix/. /app/code/ && \
mkdir -p /app/code/bin && \
cp /usr/bin/apisix /app/code/bin/
# Copy configuration template
COPY config.yaml /app/code/conf/config.yaml
# Copy start script
COPY start.sh /app/code/start.sh
RUN chmod +x /app/code/start.sh
# Set proper permissions
RUN groupadd -r cloudron && useradd -r -g cloudron cloudron && chown -R cloudron:cloudron /app/code /app/data
# Configure working directory
WORKDIR /app/code
# Expose ports
EXPOSE 9080 9443
# Start the application as cloudron user
CMD ["/usr/bin/sudo", "-E", "-u", "cloudron", "/app/code/start.sh"]

View File

@@ -0,0 +1 @@
# This is a placeholder config.yaml. It will be overwritten by start.sh

View File

@@ -0,0 +1 @@
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -euxo pipefail
# Set APISIX prefix to /app/code
PREFIX=/app/code
# Log file for APISIX output
LOG_FILE="/app/data/apisix.log"
# Ensure /app/data/conf exists
mkdir -p /app/data/conf
# Generate APISIX configuration (config.yaml) to connect to Cloudron etcd
cat <<EOF > /app/data/conf/config.yaml
apisix:
etcd:
host:
- "http://${CLOUDRON_ETCD_HOST}:${CLOUDRON_ETCD_PORT}"
prefix: "/apisix"
timeout: 30
deployment:
admin:
admin_key:
- name: admin
key: ${CLOUDRON_APP_SECRET}
role: admin
# Other APISIX configuration can go here if needed
EOF
# Print generated config.yaml and environment variables for debugging
cat /app/data/conf/config.yaml >> "${LOG_FILE}" 2>&1
env >> "${LOG_FILE}" 2>&1
# Set APISIX_CONF_FILE environment variable
export APISIX_CONF_FILE=/app/data/conf/config.yaml
# Initialize APISIX
/app/code/bin/apisix init >> "${LOG_FILE}" 2>&1
# Initialize etcd connection for APISIX
/app/code/bin/apisix init_etcd >> "${LOG_FILE}" 2>&1
# Start OpenResty (APISIX server)
/usr/local/openresty/bin/openresty -p ${PREFIX} -g 'daemon off;' >> "${LOG_FILE}" 2>&1 &
# Tail the log file to keep the container running and show output
tail -f "${LOG_FILE}"

View File

@@ -0,0 +1,44 @@
{
"id": "net.consuldemocracy.cloudron",
"title": "Consul Democracy",
"author": "Consul Democracy Community",
"description": "Open Government and E-Participation Web Software",
"tagline": "The most comprehensive citizen participation platform",
"version": "1.0.0",
"healthCheckPath": "/",
"httpPort": 8000,
"addons": {
"localstorage": {},
"postgresql": {
"version": "14"
},
"ldap": {},
"sendmail": {}
},
"manifestVersion": 2,
"website": "https://consuldemocracy.org",
"contactEmail": "info@consuldemocracy.org",
"icon": "file://logo.png",
"tags": [
"democracy",
"participation",
"open-government",
"rails"
],
"dockerImage": "{origin}/consuldemocracy",
"memoryLimit": 1024,
"documentationUrl": "https://docs.consuldemocracy.org/",
"forumUrl": "https://github.com/consuldemocracy/consuldemocracy/discussions",
"minBoxVersion": "7.0.0",
"mediaLinks": [],
"changelog": "Initial version",
"postInstallMessage": "Consul Democracy has been successfully installed! The default administrator credentials are:\n\nUsername: admin@example.org\nPassword: password\n\nPlease login and change these immediately.",
"configurePath": "/admin",
"backup": {
"backupScriptPath": "/app/code/backup.sh"
},
"sso": {
"loginPath": "/users/sign_in",
"callbackPath": "/oauth/callback"
}
}

View File

@@ -0,0 +1,114 @@
# Consul Democracy - Cloudron Build Notes
## Overview
Consul Democracy is an open-source citizen participation and open government platform, originally developed for the Madrid City government. This package enables easy deployment on the Cloudron platform with full integration of Cloudrons authentication, database, and email systems.
## Prerequisites
- A running Cloudron instance (version 7.0.0 or later)
- Basic familiarity with Cloudrons CLI for package development
- Git installed on your local machine
## Building the Package
1. Clone this repository:
```bash
git clone https://github.com/your-username/cloudron-consuldemocracy.git
cd cloudron-consuldemocracy
```
2. Install the Cloudron CLI if you havent already:
```bash
npm install -g cloudron
```
3. Login to your Cloudron:
```bash
cloudron login https://my.example.com
```
4. Build and install the package:
```bash
cloudron build
cloudron install —image consuldemocracy
```
## Configuration
### Post-Installation
After installation, the app will be available at your configured domain. The initial admin credentials are:
- Username: admin@example.org
- Password: password
**Important:** Change these credentials immediately after logging in.
### LDAP Integration
The package is configured to use Cloudrons LDAP server for authentication. Users who have access to the app through Cloudrons access control panel will be able to log in using their Cloudron credentials.
### OIDC Integration
For enhanced security, the package also supports Cloudrons OIDC provider. This is automatically configured during installation.
### Email Configuration
The package is configured to use Cloudrons SMTP server for sending emails. No additional configuration is needed.
## Customization
### Environment Variables
You can customize the app by setting environment variables in the Cloudron app configuration:
- `CONSUL_CUSTOM_LOGO`: URL to a custom logo
- `CONSUL_ORGANIZATION_NAME`: Name of your organization
- `CONSUL_THEME_COLOR`: Primary theme color (hex code)
### Filesystem Structure
- `/app/data/files`: Persistent storage for uploaded files
- `/app/data/images`: Persistent storage for uploaded images
- `/app/data/log`: Application logs
- `/app/data/tmp`: Temporary files
## Troubleshooting
### Common Issues
1. **Database Migration Errors**:
Check the app logs for specific error messages:
```bash
cloudron logs -f
```
2. **Authentication Issues**:
Ensure that the LDAP configuration is correct and that users have been granted access to the app in Cloudrons access control panel.
3. **Email Delivery Problems**:
Verify that the Cloudron mail addon is properly configured.
### Support
For issues specific to this package:
- Create an issue in the GitHub repository
- Contact the maintainer at: your-email@example.com
For issues with Consul Democracy itself:
- Visit the [Consul Democracy documentation](https://docs.consuldemocracy.org/)
- Check the [GitHub issues](https://github.com/consuldemocracy/consuldemocracy/issues)
## Updates and Maintenance
To update the app:
1. Pull the latest changes from the repository
2. Rebuild the package:
```bash
cloudron build
cloudron update —app consuldemocracy
```
Regular database backups are automatically handled by Cloudrons backup system.

View File

@@ -0,0 +1,93 @@
FROM cloudron/base:4.2.0
# Install dependencies
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
pkg-config \
git \
curl \
ruby-full \
nodejs \
npm \
imagemagick \
libpq-dev \
libxml2-dev \
libxslt1-dev \
zlib1g-dev \
libyaml-dev \
libssl-dev \
libreadline-dev \
supervisor \
nginx \
&& rm -rf /var/lib/apt/lists/*
# Update npm and install yarn
RUN npm install -g yarn
# Set Ruby and NodeJS versions
ENV RUBY_VERSION=3.2.8
ENV NODE_VERSION=18.20.3
# Ensure correct nodejs version (Node.js is already installed in base image)
RUN n ${NODE_VERSION}
# Create app directory structure
RUN mkdir -p /app/code /app/data /tmp/data
# Clone the app
RUN git clone https://github.com/consuldemocracy/consuldemocracy.git /app/code
WORKDIR /app/code
# Install bundler
RUN gem install bundler
# Install gems
RUN bundle install --deployment --without development test
# Install JavaScript dependencies
RUN yarn install
# Precompile assets
RUN SECRET_KEY_BASE=precompilation_key RAILS_ENV=production bundle exec rake assets:precompile
# Configure Nginx
RUN rm -f /etc/nginx/sites-enabled/default
COPY nginx.conf /etc/nginx/sites-enabled/consuldemocracy.conf
# Configure Supervisor
COPY supervisord.conf /etc/supervisor/conf.d/consuldemocracy.conf
# Add initialization script for /app/data
COPY init-data.sh /app/code/
RUN chmod +x /app/code/init-data.sh
# Copy backup script
COPY backup.sh /app/code/
RUN chmod +x /app/code/backup.sh
# Copy database configuration
COPY database.yml /app/code/config/database.yml
# Copy secrets configuration template
COPY secrets.yml /app/code/config/secrets.yml
# Add LDAP configuration
COPY ldap.yml /app/code/config/ldap.yml
# Copy oauth integration config
COPY oauth.rb /app/code/config/initializers/oauth.rb
# Copy the startup script
COPY start.sh /app/code/
RUN chmod +x /app/code/start.sh
# Set appropriate permissions
RUN chown -R cloudron:cloudron /app/code
# Configure app for production
ENV RAILS_ENV=production
ENV RAILS_SERVE_STATIC_FILES=true
# Entrypoint
CMD ["/app/code/start.sh"]

View File

@@ -0,0 +1,23 @@
#!/bin/bash
set -e
echo "Performing Consul Democracy backup..."
# The Cloudron backup system will automatically handle:
# 1. /app/data
# 2. PostgreSQL database
# We don't need any custom backup logic as Cloudron handles
# both the database and the data directory.
# In case of any application-specific backup needs:
# 1. Run any pre-backup tasks
cd /app/code
RAILS_ENV=production bundle exec rake tmp:clear
# 2. Ensure all user uploads are synced
sync
echo "Backup preparation complete"
exit 0

View File

@@ -0,0 +1,18 @@
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
development:
<<: *default
database: consuldemocracy_development
test:
<<: *default
database: consuldemocracy_test
production:
<<: *default
url: <%= ENV['DATABASE_URL'] %>
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 20 } %>

View File

@@ -0,0 +1,39 @@
#!/bin/bash
set -e
echo "Initializing data directory..."
# Check if data directories exist, if not create them
mkdir -p /app/data/files
mkdir -p /app/data/images
mkdir -p /app/data/log
mkdir -p /app/data/tmp
# Generate a secret key base if it doesn't exist
if [ ! -f /app/data/secret_key_base ]; then
echo "Generating secret key base..."
openssl rand -hex 64 > /app/data/secret_key_base
chmod 600 /app/data/secret_key_base
fi
# Create symlinks from app to data directory
if [ ! -L /app/code/storage ]; then
ln -sf /app/data/files /app/code/storage
fi
if [ ! -L /app/code/public/uploads ]; then
ln -sf /app/data/images /app/code/public/uploads
fi
if [ ! -L /app/code/log ]; then
ln -sf /app/data/log /app/code/log
fi
if [ ! -L /app/code/tmp ]; then
ln -sf /app/data/tmp /app/code/tmp
fi
# Set proper permissions
chown -R cloudron:cloudron /app/data
echo "Data directory initialized."

View File

@@ -0,0 +1,15 @@
production:
enabled: true
host: <%= ENV['LDAP_HOST'] %>
port: <%= ENV['LDAP_PORT'] %>
ssl: true
admin_user: <%= ENV['LDAP_ADMIN_USER'] %>
admin_password: <%= ENV['LDAP_ADMIN_PASSWORD'] %>
base: <%= ENV['LDAP_BASE'] %>
user_filter: "(uid=%{username})"
group_base: <%= ENV['CLOUDRON_LDAP_GROUPS_BASE_DN'] %>
required_groups:
- <%= ENV['CLOUDRON_LDAP_GROUPS_BASE_DN'] %>
attribute_mapping:
email: mail
name: displayName

View File

@@ -0,0 +1,47 @@
server {
listen 8000;
server_name _;
root /app/code/public;
client_max_body_size 100M;
# Handle asset requests
location ~ ^/(assets|packs)/ {
expires max;
add_header Cache-Control public;
}
# Proxy requests to the Rails application
location / {
try_files $uri @passenger;
}
location @passenger {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Port $server_port;
# Forward the original request scheme (http or https)
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
# Needed for Cloudron authentication
proxy_set_header X-Cloudron-Proxy-Port 8000;
# Proxy to the Rails application served by Puma
proxy_pass http://unix:/run/consuldemocracy.sock;
proxy_redirect off;
}
# Error pages
error_page 500 502 503 504 /500.html;
error_page 404 /404.html;
error_page 422 /422.html;
# Logging
access_log /dev/stdout;
error_log /dev/stderr;
}

View File

@@ -0,0 +1,29 @@
# Configure OAuth integration with Cloudron
if ENV['CLOUDRON_OIDC_IDENTIFIER'] && Rails.env.production?
Rails.application.config.middleware.use OmniAuth::Builder do
provider :openid_connect, {
name: :cloudron,
scope: [:openid, :email, :profile],
response_type: :code,
uid_field: 'sub',
discovery: true,
client_options: {
identifier: ENV['CLOUDRON_OIDC_CLIENT_ID'],
secret: ENV['CLOUDRON_OIDC_CLIENT_SECRET'],
redirect_uri: "https://#{ENV['CLOUDRON_APP_DOMAIN']}/oauth/callback",
port: 443,
scheme: 'https',
host: "#{ENV['CLOUDRON_APP_DOMAIN']}",
discovery_document: ENV['CLOUDRON_OIDC_IDENTIFIER']
},
client_auth_method: 'secret_basic'
}
end
# Map additional user attributes from Cloudron OIDC
OmniAuth::Strategies::OAuth2.class_eval do
def callback_url
full_host + script_name + callback_path
end
end
end

View File

@@ -0,0 +1,21 @@
default: &default
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
server_name: <%= ENV["CLOUDRON_APP_DOMAIN"] %>
smtp_settings:
address: <%= ENV["SMTP_ADDRESS"] %>
port: <%= ENV["SMTP_PORT"] %>
domain: <%= ENV["SMTP_DOMAIN"] %>
user_name: <%= ENV["SMTP_USER_NAME"] %>
password: <%= ENV["SMTP_PASSWORD"] %>
authentication: "login"
enable_starttls_auto: true
mailer_sender: <%= "noreply@#{ENV['CLOUDRON_APP_DOMAIN']}" %>
development:
<<: *default
test:
<<: *default
production:
<<: *default

View File

@@ -0,0 +1,45 @@
#!/bin/bash
set -e
echo "Starting Consul Democracy..."
# Initialize the data directory if it doesn't exist
/app/code/init-data.sh
cd /app/code
# Setup environment variables
export DATABASE_URL="postgresql://${CLOUDRON_POSTGRESQL_USERNAME}:${CLOUDRON_POSTGRESQL_PASSWORD}@${CLOUDRON_POSTGRESQL_HOST}:${CLOUDRON_POSTGRESQL_PORT}/${CLOUDRON_POSTGRESQL_DATABASE}"
export SECRET_KEY_BASE=$(cat /app/data/secret_key_base)
export RAILS_ENV=production
export RAILS_SERVE_STATIC_FILES=true
export RAILS_LOG_TO_STDOUT=true
# Configure email settings
export SMTP_ADDRESS=${CLOUDRON_MAIL_SMTP_SERVER}
export SMTP_PORT=${CLOUDRON_MAIL_SMTP_PORT}
export SMTP_DOMAIN=${CLOUDRON_APP_DOMAIN}
export SMTP_USER_NAME=${CLOUDRON_MAIL_SMTP_USERNAME}
export SMTP_PASSWORD=${CLOUDRON_MAIL_SMTP_PASSWORD}
# LDAP Setup for Cloudron integration
export LDAP_HOST=${CLOUDRON_LDAP_SERVER}
export LDAP_PORT=${CLOUDRON_LDAP_PORT}
export LDAP_ADMIN_USER=${CLOUDRON_LDAP_BIND_DN}
export LDAP_ADMIN_PASSWORD=${CLOUDRON_LDAP_BIND_PASSWORD}
export LDAP_BASE=${CLOUDRON_LDAP_USERS_BASE_DN}
# Run db migrations if needed
echo "Running database migrations..."
bundle exec rake db:migrate
# Seed the database if it's the first run
if [ ! -f /app/data/.initialized ]; then
echo "First run detected, seeding the database..."
bundle exec rake db:seed
touch /app/data/.initialized
fi
# Start the application server via supervisord
echo "Starting supervisord..."
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf

View File

@@ -0,0 +1,32 @@
[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:rails]
directory=/app/code
command=bundle exec puma -e production -b unix:///run/consuldemocracy.sock
user=cloudron
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=RAILS_ENV=production,RAILS_LOG_TO_STDOUT=true,RAILS_SERVE_STATIC_FILES=true
[program:sidekiq]
directory=/app/code
command=bundle exec sidekiq -e production
user=cloudron
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=RAILS_ENV=production,RAILS_LOG_TO_STDOUT=true

View File

@@ -0,0 +1,30 @@
{
"id": "com.easygate.cloudron",
"title": "Easy-gate",
"author": "r7wx",
"description": "A simple web application designed to serve as the central hub for your self-hosted infrastructure. Easy-gate provides real-time parsing of services and notes from a configuration file.",
"tagline": "A gate to your self-hosted infrastructure",
"version": "1.0.0",
"healthCheckPath": "/",
"httpPort": 8080,
"addons": {
"localstorage": {}
},
"manifestVersion": 2,
"website": "https://github.com/r7wx/easy-gate",
"contactEmail": "support@cloudron.io",
"icon": "logo.png",
"tags": [
"dashboard",
"infrastructure",
"services",
"homepage"
],
"env": {
"EASY_GATE_CONFIG": "/app/data/easy-gate.json",
"EASY_GATE_ROOT_PATH": "/app/data"
},
"configurePath": "/",
"minBoxVersion": "7.0.0",
"postInstallMessage": "Easy-gate has been successfully installed. You can now configure your services in the /app/data/easy-gate.json file. By default, Easy-gate runs behind Cloudron's proxy (EASY_GATE_BEHIND_PROXY=true). More configuration options available at https://github.com/r7wx/easy-gate"
}

View File

@@ -0,0 +1,41 @@
FROM cloudron/base:4.2.0
# Adding non-free repo for any potential dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
wget \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Set up directory structure
RUN mkdir -p /app/code /app/data /tmp/data
# Default config file
COPY easy-gate.json /tmp/data/easy-gate.json
# Download and install the latest Easy-gate release
RUN mkdir -p /tmp/easy-gate && \
cd /tmp/easy-gate && \
LATEST_VERSION=$(wget -qO- https://api.github.com/repos/r7wx/easy-gate/releases/latest | grep tag_name | cut -d '"' -f 4) && \
wget -q https://github.com/r7wx/easy-gate/releases/download/${LATEST_VERSION}/easy-gate_${LATEST_VERSION#v}_linux_amd64.tar.gz && \
tar -xzf easy-gate_${LATEST_VERSION#v}_linux_amd64.tar.gz && \
mv easy-gate /app/code/ && \
chmod +x /app/code/easy-gate && \
rm -rf /tmp/easy-gate
# Prepare start script
COPY start.sh /app/code/
RUN chmod +x /app/code/start.sh
# Set proper permissions
RUN chown -R cloudron:cloudron /app/code /app/data /tmp/data
# Configure working directory and user
WORKDIR /app/code
USER cloudron
# Expose the port the app runs on
EXPOSE 8080
# Start the application
CMD ["/app/code/start.sh"]

View File

@@ -0,0 +1,147 @@
# Easy-gate Build Notes for Cloudron
This document provides instructions for building, testing, and deploying Easy-gate to your Cloudron instance.
## Overview
Easy-gate is a simple web application designed to serve as the central hub for your self-hosted infrastructure. It allows you to organize and access all your self-hosted services from a single dashboard.
Key features:
- Real-time parsing of services and notes from a configuration file (JSON/YAML)
- Ability to assign items to specific user groups based on IP addresses
- Organization of services into categories
- Customizable theme and icons
## Building the Package
### Prerequisites
- A Linux environment with Docker installed
- Cloudron CLI tool installed (`npm install -g cloudron`)
- Authenticated with your Cloudron instance (`cloudron login`)
### Build Steps
1. Create a directory for your build and copy all files into it:
```bash
mkdir easy-gate-build
cd easy-gate-build
# Copy CloudronManifest.json, Dockerfile, start.sh, and easy-gate.json
```
2. Create a logo.png file for the icon or download one from the Easy-gate repository.
3. Build the package:
```bash
cloudron build
```
This command will create a package file (usually named `easy-gate-1.0.0.tar.gz`).
## Testing Locally
You can test the Docker container locally before deploying to Cloudron:
```bash
# Build the Docker image
docker build -t easy-gate-local .
# Run the container
docker run -p 8080:8080 -e EASY_GATE_BEHIND_PROXY=true easy-gate-local
```
Access the dashboard at http://localhost:8080 to verify it works correctly.
## Deploying to Cloudron
1. Upload the built package to your Cloudron:
```bash
cloudron install —app easy-gate.example.com
```
2. Or, if you want to update an existing installation:
```bash
cloudron update —app easy-gate.example.com
```
3. Configure your Easy-gate instance:
After installation, youll need to edit the configuration file to add your services. You can do this in two ways:
### Option 1: Using Cloudron File Manager
1. Go to your Cloudron dashboard
2. Click on the Easy-gate application
3. Go to “Files” tab
4. Navigate to `/app/data/`
5. Edit `easy-gate.json`
### Option 2: SSH Access
1. SSH into your Cloudron server
2. Access the apps data directory:
```bash
cloudron exec —app easy-gate.example.com
```
3. Edit the configuration file:
```bash
nano /app/data/easy-gate.json
```
## Configuration File Structure
The configuration file uses the following structure:
```json
{
“title”: “My Dashboard”,
“theme”: {
“background”: “#f8f9fa”,
“foreground”: “#212529”,
“custom_css”: “”
},
“groups”: [
{
“name”: “group-name”,
“subnet”: “192.168.1.1/24”
}
],
“categories”: [
{
“name”: “Category Name”,
“services”: [
{
“name”: “Service Name”,
“url”: “https://service.example.com”,
“description”: “Service Description”,
“icon”: “”,
“groups”: [“group-name”]
}
]
}
],
“notes”: [
{
“name”: “Note Title”,
“text”: “Note Content”,
“groups”: [“group-name”]
}
],
“behind_proxy”: true
}
```
## Troubleshooting
- If you encounter “502 Bad Gateway” errors, check that the application is running inside the container: `cloudron logs -f —app easy-gate.example.com`
- Make sure the `behind_proxy` setting is set to `true` in your configuration file
- Verify that the user groups and subnets are configured correctly
- Check the logs for any specific error messages
## Maintenance
Easy-gate is designed to be low-maintenance. To update to a newer version, simply rebuild the package with the latest release and update your Cloudron app.

View File

@@ -0,0 +1,69 @@
{
"title": "My Self-Hosted Infrastructure",
"theme": {
"background": "#f8f9fa",
"foreground": "#212529",
"custom_css": ""
},
"groups": [
{
"name": "internal",
"subnet": "192.168.1.1/24"
},
{
"name": "admin",
"subnet": "10.8.0.1/24"
}
],
"categories": [
{
"name": "Applications",
"services": [
{
"name": "Cloudron",
"url": "https://my.example.com",
"description": "My Cloudron Dashboard",
"icon": "",
"groups": []
}
]
},
{
"name": "Media",
"services": [
{
"name": "Jellyfin",
"url": "https://jellyfin.example.com",
"description": "Media Server",
"icon": "",
"groups": []
}
]
},
{
"name": "Monitoring",
"services": [
{
"name": "Grafana",
"url": "https://grafana.example.com",
"description": "Monitoring Dashboard",
"icon": "",
"groups": ["admin"]
}
]
}
],
"notes": [
{
"name": "Welcome to Easy-gate",
"text": "This is your new Easy-gate dashboard. Edit this configuration file to customize your services and notes.",
"groups": []
},
{
"name": "For Administrators",
"text": "Admin-only information can be seen here when connecting from the admin subnet.",
"groups": ["admin"]
}
],
"behind_proxy": true
}

View File

@@ -0,0 +1,20 @@
#!/bin/bash
set -e
# Initialize data directory if it doesn't exist
if [ ! -f /app/data/easy-gate.json ]; then
echo "Initializing Easy-gate with default configuration..."
cp /tmp/data/easy-gate.json /app/data/
chown cloudron:cloudron /app/data/easy-gate.json
fi
# Set environment variables
export EASY_GATE_CONFIG="/app/data/easy-gate.json"
export EASY_GATE_ROOT_PATH="/app/data"
export EASY_GATE_BEHIND_PROXY="true"
echo "Starting Easy-gate with configuration at ${EASY_GATE_CONFIG}..."
echo "Easy-gate is configured to run behind a proxy (EASY_GATE_BEHIND_PROXY=true)"
# Run the application
exec /app/code/easy-gate

View File

@@ -0,0 +1,30 @@
{
"id": "org.elabftw.cloudron",
"title": "eLabFTW",
"author": "Nicolas CARPi",
"description": "Electronic laboratory notebook to track experiments, manage protocols, store laboratory inventory, communicate with others and more. Your best lab companion.",
"tagline": "Electronic lab notebook for researchers",
"version": "1.0.0",
"healthCheckPath": "/",
"httpPort": 8000,
"addons": {
"mysql": {},
"localstorage": {}
},
"manifestVersion": 2,
"website": "https://www.elabftw.net",
"contactEmail": "support@example.com",
"icon": "file://logo.png",
"memoryLimit": 1024,
"tags": ["science", "lab", "research", "notebook", "eln"],
"minBoxVersion": "7.4.0",
"postInstallMessage": "eLabFTW has been successfully installed! You will need to create a Sysadmin account when you first access the application.",
"documentationUrl": "https://doc.elabftw.net/",
"forwardedHeaders": ["X-Forwarded-For", "X-Forwarded-Proto", "X-Forwarded-Host"],
"tcpPorts": {},
"optionalSso": {
"ldap": {
"enabled": true
}
}
}

View File

@@ -0,0 +1,59 @@
FROM cloudron/base:4.2.0
# Install required packages
RUN apt-get update && \
apt-get install -y \
php-cli \
php-fpm \
php-mysql \
php-curl \
php-gd \
php-intl \
php-mbstring \
php-xml \
php-zip \
php-bcmath \
nginx \
supervisor \
curl \
zip \
unzip \
git \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Install Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Get the latest eLabFTW release
WORKDIR /app/code
RUN git clone https://github.com/elabftw/elabftw.git . && \
composer install --no-dev --optimize-autoloader
# Configure NGINX
COPY nginx.conf /etc/nginx/sites-available/default
# Prepare directory structure
RUN mkdir -p /app/data/uploads /app/data/config /app/data/logs /run/php && \
chown -R cloudron:cloudron /app/data /run/php
# Copy initialization data
RUN mkdir -p /tmp/data/config /tmp/data/uploads /tmp/data/logs && \
cp -r /app/code/config-example.yml /tmp/data/config/config.yml && \
chown -R cloudron:cloudron /tmp/data
# Copy start script and supervisor config
COPY start.sh /app/code/
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
RUN chmod +x /app/code/start.sh
# Configure PHP-FPM
RUN sed -i 's/www-data/cloudron/g' /etc/php/*/fpm/pool.d/www.conf && \
sed -i 's/listen = \/run\/php\/php[0-9]\.[0-9]-fpm.sock/listen = \/run\/php\/php-fpm.sock/g' /etc/php/*/fpm/pool.d/www.conf && \
echo 'catch_workers_output = yes' >> /etc/php/*/fpm/pool.d/www.conf
# Create logo image
RUN curl -o /app/code/logo.png https://raw.githubusercontent.com/elabftw/elabftw/master/src/ts/img/logo.png
WORKDIR /app/code
CMD ["/app/code/start.sh"]

View File

@@ -0,0 +1,109 @@
# eLabFTW Cloudron Package Build Notes
This document provides instructions for building, testing, and deploying the eLabFTW Cloudron package.
## Package Overview
This package deploys eLabFTW, an open-source electronic laboratory notebook (ELN) for researchers, on Cloudron. The package:
- Uses the MySQL addon for database storage
- Uses the localstorage addon for file storage
- Includes NGINX and PHP-FPM configuration
- Supports optional LDAP authentication through Cloudron
## Building the Package
1. Create a new directory for your package:
```bash
mkdir elabftw-cloudron
cd elabftw-cloudron
```
2. Save all the provided files to this directory:
- CloudronManifest.json
- Dockerfile
- start.sh
- nginx.conf
- supervisord.conf
3. Make the start.sh file executable:
```bash
chmod +x start.sh
```
4. Download the eLabFTW logo for the package icon:
```bash
curl -o logo.png https://raw.githubusercontent.com/elabftw/elabftw/master/src/ts/img/logo.png
```
5. Build the package:
```bash
cloudron build
```
## Testing the Package
1. Install the package on your Cloudron for testing:
```bash
cloudron install —location elabftw.example.com
```
2. After installation, visit the application URL and complete the initial setup:
- Create the Sysadmin account
- Configure your teams and user groups
- Set up any initial templates or protocols
3. Test the following functionality:
- User authentication (local accounts)
- File uploads (should be stored in /app/data/uploads)
- Database connection (should be using Cloudron MySQL)
- LDAP authentication (if enabled)
- General application functionality
## Deploying to Production
1. Once testing is complete, you can deploy to production:
```bash
cloudron install —location elabftw.yourdomain.com
```
2. For production use, consider:
- Setting up regular backups of the Cloudron app
- Configuring LDAP authentication if needed (via Cloudron UI)
- Adjusting memory limits in CloudronManifest.json if necessary based on usage
## Post-Installation
After installation, youll need to:
1. Create a Sysadmin account when first accessing the application
2. Configure teams and user groups
3. Set up experiment templates and protocols as needed
4. Consider enabling and configuring LDAP authentication for easier user management
## Troubleshooting
- Check logs with `cloudron logs -f elabftw`
- If database issues occur, verify the MySQL addon is properly configured
- For file storage issues, check permissions on /app/data directories
- For authentication issues, verify LDAP configuration (if using LDAP)
## Updates
When a new version of eLabFTW is released:
1. Update the git clone command in the Dockerfile to point to the latest release (or specific tag)
2. Rebuild and update your package:
```bash
cloudron build
cloudron update —app elabftw.yourdomain.com
```
## Customization
You can customize the package by:
1. Modifying the config.yml template in /tmp/data/config to set default values
2. Adjusting PHP settings in the Dockerfile or php.ini
3. Modifying NGINX configuration for special requirements
4. Adjusting memory limits in CloudronManifest.json based on usage patterns

View File

@@ -0,0 +1,38 @@
server {
listen 8000;
server_name _;
root /app/code/web;
index index.php;
client_max_body_size 100M;
access_log /dev/stdout;
error_log /dev/stderr;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS on;
# Forward Cloudron proxy headers
fastcgi_param HTTP_X_FORWARDED_FOR $http_x_forwarded_for;
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
fastcgi_param HTTP_X_FORWARDED_HOST $http_x_forwarded_host;
}
# Deny access to other PHP files
location ~ \.php$ {
return 404;
}
# Rewrite app routes
location @rewriteapp {
rewrite ^(.*)$ /index.php/$1 last;
}
}

View File

@@ -0,0 +1,53 @@
#!/bin/bash
set -e
# Create directory structure if it doesn't exist
if [ ! -d /app/data/uploads ]; then
mkdir -p /app/data/uploads
cp -r /tmp/data/uploads/* /app/data/uploads/ 2>/dev/null || true
chown -R cloudron:cloudron /app/data/uploads
fi
if [ ! -d /app/data/logs ]; then
mkdir -p /app/data/logs
cp -r /tmp/data/logs/* /app/data/logs/ 2>/dev/null || true
chown -R cloudron:cloudron /app/data/logs
fi
if [ ! -f /app/data/config/config.yml ]; then
mkdir -p /app/data/config
cp -r /tmp/data/config/* /app/data/config/ 2>/dev/null || true
# Configure database connection
sed -i "s/host: .*/host: ${CLOUDRON_MYSQL_HOST}/" /app/data/config/config.yml
sed -i "s/port: .*/port: ${CLOUDRON_MYSQL_PORT}/" /app/data/config/config.yml
sed -i "s/database: .*/database: ${CLOUDRON_MYSQL_DATABASE}/" /app/data/config/config.yml
sed -i "s/username: .*/username: ${CLOUDRON_MYSQL_USERNAME}/" /app/data/config/config.yml
sed -i "s/password: .*/password: ${CLOUDRON_MYSQL_PASSWORD}/" /app/data/config/config.yml
# Configure paths
sed -i "s|uploads: .*|uploads: /app/data/uploads|" /app/data/config/config.yml
sed -i "s|logs: .*|logs: /app/data/logs|" /app/data/config/config.yml
# Configure LDAP if enabled
if [ "${CLOUDRON_LDAP_ENABLED}" == "true" ]; then
# Update LDAP settings in config
sed -i "s/ldap_enabled: .*/ldap_enabled: true/" /app/data/config/config.yml
sed -i "s/ldap_host: .*/ldap_host: ${CLOUDRON_LDAP_SERVER}/" /app/data/config/config.yml
sed -i "s/ldap_port: .*/ldap_port: ${CLOUDRON_LDAP_PORT}/" /app/data/config/config.yml
sed -i "s/ldap_username: .*/ldap_username: ${CLOUDRON_LDAP_BIND_DN}/" /app/data/config/config.yml
sed -i "s/ldap_password: .*/ldap_password: ${CLOUDRON_LDAP_BIND_PASSWORD}/" /app/data/config/config.yml
sed -i "s/ldap_base_dn: .*/ldap_base_dn: ${CLOUDRON_LDAP_USERS_BASE_DN}/" /app/data/config/config.yml
fi
chown -R cloudron:cloudron /app/data/config
fi
# Create a symlink to the config file
ln -sf /app/data/config/config.yml /app/code/config.yml
# Set proper permissions
chown -R cloudron:cloudron /app/data
# Start the supervisord
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf

View File

@@ -0,0 +1,24 @@
[supervisord]
nodaemon=true
logfile=/dev/stdout
logfile_maxbytes=0
[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autostart=true
autorestart=true
priority=10
[program:php-fpm]
command=/usr/sbin/php-fpm8.1 -F
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autostart=true
autorestart=true
priority=5

View File

@@ -0,0 +1,46 @@
{
"id": "com.getgrist.cloudron",
"title": "Grist",
"author": "Grist Labs",
"description": "A modern, open source spreadsheet that goes beyond the grid. Grist combines the flexibility of a spreadsheet with the robustness of a database to organize your data your way.",
"tagline": "Modern relational spreadsheet with Python formulas",
"version": "1.0.0",
"healthCheckPath": "/healthz",
"httpPort": 8080,
"addons": {
"localstorage": {},
"postgresql": {
"userName": "grist",
"databaseName": "grist"
}
},
"manifestVersion": 2,
"website": "https://www.getgrist.com/",
"documentationUrl": "https://support.getgrist.com/",
"contactEmail": "support@getgrist.com",
"icon": "file://logo.png",
"memoryLimit": 1024,
"tags": ["spreadsheet", "database", "python", "dashboard"],
"minBoxVersion": "7.0.0",
"installationNotes": {
"en": "The default administrator account is set to your Cloudron email. Access Grist at the configured subdomain."
},
"postInstallationNotes": {
"en": "Grist has been successfully installed. The administrator account is set to your Cloudron email. Sign in using your Cloudron account credentials."
},
"forumUrl": "https://community.getgrist.com/",
"mediaLinks": [
"https://www.getgrist.com/assets/images/grist-demo.png"
],
"authentication": {
"loginPath": "/auth/login",
"logoutPath": "/auth/logout",
"impl": "oauth",
"oauth": {
"clientId": "{{cloudronOAuthClientId}}",
"clientSecret": "{{cloudronOAuthClientSecret}}",
"callbackPath": "/oauth2/callback",
"scope": "profile email"
}
}
}

View File

@@ -0,0 +1,79 @@
FROM cloudron/base:4.2.0
# Add Cloudron specific environment
ENV CLOUDRON=1 \
HOME=/app/data \
LC_ALL=C.UTF-8 \
LANG=C.UTF-8 \
USER=cloudron \
PORT=8080 \
PYTHON_VERSION=3 \
PYTHON_VERSION_ON_CREATION=3 \
DEBUG=0
# Install required dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
wget \
gnupg \
supervisor \
python3 \
python3-pip \
python3-setuptools \
python3-wheel \
python3-venv \
build-essential \
pkg-config \
xvfb \
xauth \
libcairo2-dev \
libpango1.0-dev \
libglib2.0-dev \
nodejs \
npm \
git \
sqlite3 \
curl \
ca-certificates && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Create required directories
RUN mkdir -p /app/code /app/data /app/pkg /app/log && \
mkdir -p /app/data/docs
# Clone Grist
WORKDIR /app/pkg
RUN git clone --depth 1 https://github.com/gristlabs/grist-core.git && \
cd grist-core && \
npm install && \
npm run build && \
cd /app/pkg
# Set up supervisor config
COPY supervisor.conf /etc/supervisor/conf.d/grist.conf
COPY nginx.conf /app/pkg/nginx.conf
# Nginx site configuration
COPY nginx-app.conf /etc/nginx/sites-available/grist
RUN ln -sf /etc/nginx/sites-available/grist /etc/nginx/sites-enabled/grist && \
rm -f /etc/nginx/sites-enabled/default
# Add scripts
COPY start.sh /app/pkg/
RUN chmod +x /app/pkg/start.sh
# Set up initialization data
COPY --chown=cloudron:cloudron init_data/ /app/pkg/init_data/
# Set ownership
RUN chown -R cloudron:cloudron /app/code /app/data /app/pkg /app/log
# Set working directory
WORKDIR /app/pkg
# Run as cloudron user
USER cloudron
# Start application
CMD ["/app/pkg/start.sh"]

View File

@@ -0,0 +1,131 @@
# Grist Cloudron Package Build Notes
## Overview
This document provides instructions for building, testing, and deploying the Grist Cloudron package. Grist is a modern, open-source spreadsheet application with database capabilities, Python formulas, and collaborative features.
## Package Components
The package includes the following files:
1. `CloudronManifest.json` - Configuration file for Cloudron
2. `Dockerfile` - Instructions for building the Docker image
3. `start.sh` - Initialization and startup script
4. `supervisor.conf` - Process management configuration
5. `nginx-app.conf` - NGINX site configuration
6. `nginx.conf` - NGINX main configuration
7. `logo.png` - Grist logo for Cloudron (needs to be added)
## Prerequisites
- Cloudron server (v7.0.0 or newer)
- Docker installed on your build machine
- Cloudron CLI installed on your build machine
## Build Instructions
1. **Prepare the package directory**
Create a directory for your package and place all the files in it:
```bash
mkdir -p grist-cloudron
cd grist-cloudron
# Copy all files into this directory
```
2. **Add the Grist logo**
Download the Grist logo and save it as `logo.png` in the package directory:
```bash
curl -o logo.png https://raw.githubusercontent.com/gristlabs/grist-core/main/static/favicon.png
```
3. **Create an initialization data directory**
```bash
mkdir -p init_data
```
4. **Build the Docker image**
```bash
cloudron build
```
## Testing the Package
1. **Install the package on your Cloudron for testing**
```bash
cloudron install —image your-docker-image-name
```
2. **Verify the installation**
Once installed, navigate to the apps URL and verify that:
- The login page appears correctly
- You can log in using your Cloudron credentials
- You can create and edit documents
- Document imports and exports work properly
- Python formulas are functioning correctly
3. **Test authentication**
Verify that:
- Authentication with Cloudron accounts works
- User permissions are applied correctly
- Logging out works properly
## Common Issues and Troubleshooting
1. **Authentication Issues**
- Check that the OAuth configuration is correct in `CloudronManifest.json`
- Verify environment variables in `start.sh` related to OIDC
2. **Database Connection Problems**
- Verify PostgreSQL addon configuration
- Check logs for database connection errors
3. **Grist Not Starting**
- Check supervisord logs: `cloudron logs -f`
- Verify that the required directories exist and have proper permissions
4. **File Upload Issues**
- Verify the `client_max_body_size` setting in the NGINX configuration
## Deployment
1. **Prepare the package for production**
```bash
cloudron build
cloudron upload
```
2. **Install from the Cloudron App Store**
After submission and approval, users can install directly from the Cloudron App Store.
## Maintenance
1. **Updating Grist**
To update Grist to a newer version:
- Update the git clone command in the `Dockerfile`
- Update the version in `CloudronManifest.json`
- Rebuild and redeploy
2. **Backing Up**
Cloudron automatically backs up:
- The PostgreSQL database
- The `/app/data` directory containing all Grist documents
## Additional Resources
- [Grist Documentation](https://support.getgrist.com/)
- [Grist GitHub Repository](https://github.com/gristlabs/grist-core)
- [Cloudron Documentation](https://docs.cloudron.io/)
- [Grist Community Forum](https://community.getgrist.com/)

View File

@@ -0,0 +1,53 @@
server {
listen 8080;
server_name localhost;
# Set maximum upload size
client_max_body_size 300M;
# Add security headers
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Frame-Options SAMEORIGIN;
add_header Referrer-Policy strict-origin-when-cross-origin;
# Main location for Grist
location / {
proxy_pass http://127.0.0.1:8484;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_read_timeout 90;
proxy_buffering off;
}
# Health check endpoint
location = /healthz {
access_log off;
add_header Content-Type text/plain;
return 200 'OK';
}
# Static file caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
proxy_pass http://127.0.0.1:8484;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
expires 30d;
add_header Cache-Control "public, no-transform";
}
# Error pages
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

View File

@@ -0,0 +1,43 @@
user cloudron;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# SSL Settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
# Logging Settings
access_log /dev/stdout;
error_log /dev/stderr;
# Gzip Settings
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# Virtual Host Configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

View File

@@ -0,0 +1,63 @@
#!/bin/bash
set -e
# Cloudron environment variables
export GRIST_APP_ROOT="/app/pkg/grist-core"
export GRIST_DATA_DIR="/app/data/docs"
export GRIST_SESSION_SECRET="${CLOUDRON_SESSION_SECRET}"
export APP_HOME_URL="${CLOUDRON_APP_URL}"
export GRIST_DOMAIN="${CLOUDRON_APP_DOMAIN}"
export GRIST_SINGLE_ORG="cloudron"
export GRIST_HIDE_UI_ELEMENTS="billing"
export GRIST_MAX_UPLOAD_ATTACHMENT_MB=100
export GRIST_MAX_UPLOAD_IMPORT_MB=300
export GRIST_SANDBOX_FLAVOR="gvisor"
export GRIST_USER_ROOT="/app/data"
export GRIST_THROTTLE_CPU="true"
export GRIST_DEFAULT_EMAIL="${CLOUDRON_ADMIN_EMAIL}"
export GRIST_FORCE_LOGIN="true"
export GRIST_SUPPORT_ANON="false"
export COOKIE_MAX_AGE=2592000000 # 30 days in milliseconds
# Setup OpenID Connect for Cloudron authentication
export GRIST_OIDC_IDP_ISSUER="${CLOUDRON_APP_ORIGIN}"
export GRIST_OIDC_IDP_CLIENT_ID="${CLOUDRON_OAUTH_CLIENT_ID}"
export GRIST_OIDC_IDP_CLIENT_SECRET="${CLOUDRON_OAUTH_CLIENT_SECRET}"
export GRIST_OIDC_IDP_SCOPES="openid profile email"
export GRIST_OIDC_SP_HOST="${CLOUDRON_APP_URL}"
export GRIST_OIDC_SP_PROFILE_EMAIL_ATTR="email"
export GRIST_OIDC_SP_PROFILE_NAME_ATTR="name"
export GRIST_OIDC_IDP_ENABLED_PROTECTIONS="PKCE,STATE"
# Database configuration using Cloudron PostgreSQL addon
export TYPEORM_TYPE="postgres"
export TYPEORM_DATABASE="${CLOUDRON_POSTGRESQL_DATABASE}"
export TYPEORM_USERNAME="${CLOUDRON_POSTGRESQL_USERNAME}"
export TYPEORM_PASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}"
export TYPEORM_HOST="${CLOUDRON_POSTGRESQL_HOST}"
export TYPEORM_PORT="${CLOUDRON_POSTGRESQL_PORT}"
export TYPEORM_LOGGING="false"
# Initialize or update data directories if they don't exist
if [ ! -d "/app/data/docs" ]; then
mkdir -p /app/data/docs
echo "Created docs directory"
fi
if [ ! -d "/app/data/home" ]; then
mkdir -p /app/data/home
echo "Created home directory"
fi
# Copy initialization data if needed
if [ -d "/app/pkg/init_data" ] && [ ! -f "/app/data/.initialized" ]; then
cp -R /app/pkg/init_data/* /app/data/
touch /app/data/.initialized
echo "Copied initialization data"
fi
# Ensure proper permissions
chown -R cloudron:cloudron /app/data
# Start supervisor to manage Grist and Nginx
exec /usr/bin/supervisord --nodaemon -c /etc/supervisor/supervisord.conf

View File

@@ -0,0 +1,32 @@
[supervisord]
nodaemon=true
logfile=/app/log/supervisord.log
logfile_maxbytes=10MB
logfile_backups=3
loglevel=info
pidfile=/run/supervisord.pid
user=cloudron
[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
priority=10
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autostart=true
autorestart=true
[program:grist]
command=bash -c "cd /app/pkg/grist-core && node sandbox/pyodide.js"
user=cloudron
environment=HOME=/app/data
directory=/app/pkg/grist-core
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autostart=true
autorestart=true
startretries=3
priority=20

View File

@@ -0,0 +1,24 @@
{
"id": "org.inventree.cloudronapp",
"title": "InvenTree",
"author": "Your Name",
"description": "InvenTree is an open-source inventory management system which provides intuitive parts management and stock control.",
"tagline": "Open Source Inventory Management System",
"version": "1.0.0",
"healthCheckPath": "/api/generic/status/",
"httpPort": 8000,
"manifestVersion": 2,
"website": "https://inventree.org",
"contactEmail": "your.email@example.com",
"icon": "logo.png",
"documentationUrl": "https://docs.inventree.org",
"memoryLimit": 1024000000,
"configurePath": "/admin",
"minBoxVersion": "7.0.0",
"changelog": "Initial version",
"addons": {
"localstorage": {},
"postgresql": {}
},
"postInstallMessage": "InvenTree has been installed. The default admin credentials are:\n\nUsername: admin\nPassword: admin\n\nPlease change the admin password after your first login."
}

View File

@@ -0,0 +1,74 @@
FROM cloudron/base:4.2.0
# Set environment variables
ENV PYTHONUNBUFFERED=1 \
DEBIAN_FRONTEND=noninteractive \
INVENTREE_HOME=/app/data \
INVENTREE_MEDIA_ROOT=/app/data/media \
INVENTREE_STATIC_ROOT=/app/data/static \
INVENTREE_SECRET_KEY_FILE=/app/data/secret_key.txt \
INVENTREE_PLUGINS_ENABLED=true \
INVENTREE_PLUGINS_DIR=/app/data/plugins \
INVENTREE_ADMIN_USER=admin \
INVENTREE_ADMIN_PASSWORD=admin \
INVENTREE_ADMIN_EMAIL=admin@example.com
# Install required packages
RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
python3-dev \
python3-venv \
build-essential \
libpq-dev \
git \
nginx \
supervisor \
&& rm -rf /var/lib/apt/lists/*
# Setup nginx for Cloudron
RUN rm /etc/nginx/sites-enabled/* \
&& sed -e 's,^ErrorLog.*,ErrorLog "/dev/stderr",' -i /etc/nginx/nginx.conf \
&& echo "daemon off;" >> /etc/nginx/nginx.conf
# Create InvenTree directories
RUN mkdir -p /app/code \
&& mkdir -p /tmp/data/media \
&& mkdir -p /tmp/data/static \
&& mkdir -p /tmp/data/plugins \
&& mkdir -p /tmp/data/env \
&& mkdir -p /tmp/data/config
# Create Python virtual environment
RUN python3 -m venv /app/code/env
# Clone InvenTree source code
RUN git clone --depth 1 https://github.com/inventree/InvenTree.git /app/code/inventree
# Install InvenTree requirements
WORKDIR /app/code/inventree
RUN /app/code/env/bin/pip install --upgrade pip \
&& /app/code/env/bin/pip install wheel \
&& /app/code/env/bin/pip install --no-cache-dir -r requirements.txt \
&& /app/code/env/bin/pip install psycopg2 gunicorn
# Create default configuration files
COPY config.yaml /tmp/data/config/config.yaml
COPY nginx.conf /etc/nginx/sites-available/inventree
RUN ln -s /etc/nginx/sites-available/inventree /etc/nginx/sites-enabled/
# Copy supervisor configuration
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Add startup script
COPY start.sh /app/code/start.sh
RUN chmod +x /app/code/start.sh
# Setup NGINX runtime directory
RUN mkdir -p /run/nginx \
&& chown -R cloudron:cloudron /run/nginx
# Expose port
EXPOSE 8000
CMD ["/app/code/start.sh"]

View File

@@ -0,0 +1,74 @@
# InvenTree Cloudron Build Notes
## Package Contents
- CloudronManifest.json - App metadata and resource configuration
- Dockerfile - Container build instructions
- start.sh - App initialization and startup script
- config.yaml - InvenTree configuration template
- nginx.conf - Web server configuration
- supervisord.conf - Process management configuration
## Build & Deploy Steps
### 1. Prepare Local Directory
```bash
mkdir -p inventree-cloudron
cd inventree-cloudron
# Copy all files into this directory
```
### 2. Build & Push to Gitea Registry
```bash
# Login to your Gitea Docker registry
docker login gitea.yourdomain.com
# Build the Docker image
docker build -t gitea.yourdomain.com/yourusername/inventree:1.0.0 .
# Push the image to your registry
docker push gitea.yourdomain.com/yourusername/inventree:1.0.0
```
### 3. Install on Cloudron
```bash
# Login to your Cloudron
cloudron login my.cloudron.example
# Install the app
cloudron install --image gitea.yourdomain.com/yourusername/inventree:1.0.0
```
### 4. Update Process
```bash
# Build with new version tag
docker build -t gitea.yourdomain.com/yourusername/inventree:1.0.1 .
docker push gitea.yourdomain.com/yourusername/inventree:1.0.1
# Update existing installation
cloudron update --app inventree.my.cloudron.example --image gitea.yourdomain.com/yourusername/inventree:1.0.1
```
## Troubleshooting
### Database Issues
If database migrations fail:
```bash
cloudron exec --app inventree.my.cloudron.example -- /app/code/env/bin/python /app/code/inventree/manage.py migrate
```
### Inspect Logs
```bash
cloudron logs --app inventree.my.cloudron.example
```
### Debug Mode
```bash
cloudron debug --app inventree.my.cloudron.example
```
## Initial Access
After installation, access InvenTree at your configured domain with:
- Username: admin
- Password: admin
**Important**: Change this password immediately after first login!

View File

@@ -0,0 +1,49 @@
# InvenTree configuration file for Cloudron
# Refer to InvenTree documentation for detailed configuration options
# Database connection settings will be provided via environment variables
# General settings
debug: False
log_level: WARNING
# Secret key will be stored in a file
secret_key_file: /app/data/secret_key.txt
# Plugin settings
plugins:
enabled: True
plugin_dir: /app/data/plugins
# File storage locations
media_root: /app/data/media
static_root: /app/data/static
# Email settings - adjust with your Cloudron email settings if needed
email:
host: localhost
port: 25
tls: false
ssl: false
sender: inventree@localhost
# Login settings
login:
default_protocol: https
allow_unverified_signup: False
allow_signup: True
signup_email_verification: False
login_confirm_days: 3
password_reset_timeout_days: 3
# Display settings
customization:
instance_name: InvenTree
default_currency: USD
base_url: "" # Will be set by environment variable in start.sh
# Server settings
server:
workers: 2
allowed_hosts:
- '*' # Cloudron handles this

View File

@@ -0,0 +1,172 @@
<!DOCTYPE html>
<html lang=" en-US ">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/assets/splide/css/splide.min.css">
<link rel="stylesheet" href="/assets/index.css">
<link rel="shortcut icon" type="image/png" href="/assets/icon/favicon.ico">
<script src="/assets/splide/js/splide.min.js"></script>
<!-- Fontawesome integration -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css">
<title>InvenTree</title>
<meta itemprop="description" name="description"
content="InvenTree is an open-source inventory management system which provides intuitive parts management and stock control. It is at the center of an ecosystem of a..." />
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>InvenTree | Intuitive Inventory Management</title>
<meta name="generator" content="Jekyll v4.3.3" />
<meta property="og:title" content="InvenTree" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="InvenTree is an open-source inventory management system which provides intuitive parts management and stock control. It is at the center of an ecosystem of addins for EDA tools, API wrapper, deeply integrated plugins and 3rd party tools." />
<meta property="og:description" content="InvenTree is an open-source inventory management system which provides intuitive parts management and stock control. It is at the center of an ecosystem of addins for EDA tools, API wrapper, deeply integrated plugins and 3rd party tools." />
<link rel="canonical" href="/404" />
<meta property="og:url" content="/404" />
<meta property="og:site_name" content="InvenTree" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="InvenTree" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebPage","description":"InvenTree is an open-source inventory management system which provides intuitive parts management and stock control. It is at the center of an ecosystem of addins for EDA tools, API wrapper, deeply integrated plugins and 3rd party tools.","headline":"InvenTree","url":"/404"}</script>
<!-- End Jekyll SEO tag -->
</head>
<body class="flex flex-col antialiased cm-gray-1 min-h-screen">
<div class="flex-none">
<header class="cm-gray-2 body-font sticky top-0 z-50 bg-gradient-to-r from-white to-secondary">
<div class="container mx-auto flex flex-wrap p-5 flex-row items-center">
<a class="flex title-font font-medium items-center cm-gray-1 mb-0 mr-2" href="/">
<img src="/assets/logo.png" alt="logo" height="32" width="32" class="h-8">
<span class="ml-3 text-xl">InvenTree</span>
</a>
<div class="flex-grow xs:flex-none"></div>
<nav class="md:mr-auto md:py-1 xs:ml-4 xs:pl-4 xs:border-l xs:border-gray-400 flex flex-wrap items-center text-base justify-center">
<a class="mr-5 hover:cm-gray-1" href="/deploy.html">Deploy</a>
<a class="mr-5 hover:cm-gray-1" href="https://docs.inventree.org/en/stable/">Docs</a>
<a class="mr-5 hover:cm-gray-1" href="/blog">Blog</a>
</nav>
</div>
</header> <article>
<h2></h2>
<h2 id="404---page-not-found">404 - Page not found</h2>
<p>This page is unkown!</p>
<p>Please go back to the last working page.</p>
</article>
</div>
<div class="flex-grow"></div>
<div class="flex-none">
<footer class="cm-gray-2 body-font">
<div class="container px-5 pt-8 mx-auto flex md:flex-row md:flex-nowrap flex-wrap flex-col">
<div class="w-64 flex-shrink-0 md:mx-0 mx-auto text-center md:text-left">
<div class="flex title-font font-medium items-center md:justify-start justify-center cm-gray-1">
<img src="/assets/logo.png" alt="logo" height="32" width="32" class="h-8">
<span class="ml-3 text-xl">InvenTree</span>
</div>
<p class="mt-2 text-sm cm-gray-3">Intuitive Inventory Management</p>
</div>
<div class="flex-grow flex flex-wrap md:pl-10 mb-1 md:mt-0 mt-10 md:text-left text-center md:justify-left justify-center">
<div class="md:w-1/4 px-4">
<h2 class="footer-categorie title-font">
Quick
</h2>
<nav class="list-none mb-10"><ul>
<li><a href="/demo.html" class="footer-link">Demo</a></li>
<li><a href="/deploy.html" class="footer-link">Deploy</a></li>
<li><a href="https://docs.inventree.org/en/stable/" class="footer-link">Docs</a></li>
<li><a href="/news" class="footer-link">News</a></li>
<li><a href="/plugins" class="footer-link">Plugin List</a></li>
</ul></nav>
</div>
<div class="md:w-1/4 px-4">
<h2 class="footer-categorie title-font">
<a href="/extend/">Ecosystem</a>
</h2>
<nav class="list-none mb-10"><ul>
<li><a href="/extend/api.html" class="footer-link">API</a></li>
<li><a href="/extend/app.html" class="footer-link">App</a></li>
<li><a href="/extend/plugin/" class="footer-link">Plugins</a></li>
<li><a href="/extend/integrate/" class="footer-link">Integrations</a></li>
</ul></nav>
</div>
<div class="md:w-1/4 px-4">
<h2 class="footer-categorie title-font">
Sitemap
</h2>
<nav class="list-none mb-10"><ul>
<li><a href="/about/" class="footer-link">About</a></li>
<li><a href="/alternatives/" class="footer-link">Alternatives</a></li>
<li><a href="/blog" class="footer-link">Blog</a></li>
<li><a href="/contribute.html" class="footer-link">Contribute</a></li>
<li><a href="/support.html" class="footer-link">Support</a></li>
</ul></nav>
</div>
</div>
</div>
<div class="bg-gray-100">
<div class="container mx-auto py-4 px-5 flex flex-wrap flex-col sm:flex-row">
<p class="cm-gray-2 text-sm text-center sm:text-left">© 2021-now InvenTree by<a href="https://github.com/inventree" rel="noopener" class="cm-gray-2 ml-1" target="_blank">@inventree</a>— website made with ♥ by<a href="https://github.com/matmair" rel="noopener" class="cm-gray-2 ml-1" target="_blank">@matmair</a></p>
<span class="inline-flex sm:ml-auto sm:mt-0 mt-2 justify-center sm:justify-start">
<span class="invisible"><a rel="me" href="https://chaos.social/@InvenTree">Mastodon</a></span>
<a href="https://github.com/inventree/inventree" alt="github repo" class="ml-3 cm-gray-3">
<img class="h-5 w-5" alt="GitHub logo" src="/assets/github.svg">
</a>
<a href="https://reddit.com/r/inventree" alt="Reddit" class="ml-3 cm-gray-3">
<img class="h-5 w-5" alt="Reddit logo" src="/assets/reddit.svg">
</a>
<a href="https://twitter.com/inventreedb" alt="Twitter" class="ml-3 cm-gray-3">
<img class="h-5 w-5" alt="Twitter logo" src="/assets/twitter.svg">
</a>
<a href="https://chaos.social/@InvenTree" rel="me" alt="Mastodon" class="ml-3 cm-gray-3">
<img class="h-5 w-5" alt="Mastodon logo" src="/assets/mastodon.svg">
</a>
</span>
</div>
</div>
</footer>
</div>
</body>
</html>

View File

@@ -0,0 +1,35 @@
server {
listen 8000; # This should match the httpPort in CloudronManifest.json
client_max_body_size 100M;
access_log /dev/stdout;
error_log /dev/stderr;
# Serve static files
location /static/ {
alias /app/data/static/;
expires 30d;
add_header Pragma public;
add_header Cache-Control "public";
}
# Serve media files
location /media/ {
alias /app/data/media/;
expires 30d;
add_header Pragma public;
add_header Cache-Control "public";
}
# Proxy requests to gunicorn
location / {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_buffering off;
}
}

View File

@@ -0,0 +1,72 @@
#!/bin/bash
set -e
# PostgreSQL configuration from Cloudron environment variables
if [ -n "${CLOUDRON_POSTGRESQL_HOST}" ]; then
export INVENTREE_DB_ENGINE="postgresql"
export INVENTREE_DB_NAME="${CLOUDRON_POSTGRESQL_DATABASE}"
export INVENTREE_DB_USER="${CLOUDRON_POSTGRESQL_USERNAME}"
export INVENTREE_DB_PASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}"
export INVENTREE_DB_HOST="${CLOUDRON_POSTGRESQL_HOST}"
export INVENTREE_DB_PORT="${CLOUDRON_POSTGRESQL_PORT}"
else
echo "PostgreSQL addon not configured!"
exit 1
fi
# Ensure data directories exist
if [ ! -d "${INVENTREE_HOME}/media" ]; then
echo "Creating media directory..."
mkdir -p "${INVENTREE_HOME}/media"
cp -rn /tmp/data/media/* "${INVENTREE_HOME}/media/" || true
fi
if [ ! -d "${INVENTREE_HOME}/static" ]; then
echo "Creating static directory..."
mkdir -p "${INVENTREE_HOME}/static"
cp -rn /tmp/data/static/* "${INVENTREE_HOME}/static/" || true
fi
if [ ! -d "${INVENTREE_HOME}/plugins" ]; then
echo "Creating plugins directory..."
mkdir -p "${INVENTREE_HOME}/plugins"
cp -rn /tmp/data/plugins/* "${INVENTREE_HOME}/plugins/" || true
fi
if [ ! -d "${INVENTREE_HOME}/config" ]; then
echo "Creating config directory..."
mkdir -p "${INVENTREE_HOME}/config"
cp -rn /tmp/data/config/* "${INVENTREE_HOME}/config/" || true
fi
# Generate secret key if it doesn't exist
if [ ! -f "${INVENTREE_SECRET_KEY_FILE}" ]; then
echo "Generating secret key..."
python3 -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())" > "${INVENTREE_SECRET_KEY_FILE}"
fi
cd /app/code/inventree
# Set InvenTree base URL (from Cloudron environment)
export INVENTREE_BASE_URL="https://${CLOUDRON_APP_DOMAIN}"
# Apply database migrations and collect static files
echo "Applying database migrations..."
/app/code/env/bin/python manage.py migrate --noinput
echo "Collecting static files..."
/app/code/env/bin/python manage.py collectstatic --noinput
# Create superuser if not exists
echo "Checking for superuser..."
DJANGO_SUPERUSER_PASSWORD="${INVENTREE_ADMIN_PASSWORD}" \
/app/code/env/bin/python manage.py createsuperuser --noinput \
--username "${INVENTREE_ADMIN_USER}" \
--email "${INVENTREE_ADMIN_EMAIL}" || true
# Set proper permissions
chown -R cloudron:cloudron "${INVENTREE_HOME}"
# Start supervisor to manage processes
echo "Starting supervisor..."
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf

View File

@@ -0,0 +1,26 @@
[supervisord]
nodaemon=true
user=root
logfile=/dev/stdout
logfile_maxbytes=0
[program:gunicorn]
command=/app/code/env/bin/gunicorn InvenTree.wsgi --bind 127.0.0.1:8001 --workers 2 --timeout 60 --preload --forwarded-allow-ips='*'
directory=/app/code/inventree
user=cloudron
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=PYTHONUNBUFFERED=1,INVENTREE_CONFIG_FILE=/app/data/config/config.yaml
[program:nginx]
command=/usr/sbin/nginx
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View File

@@ -0,0 +1,40 @@
{
"id": "io.jenkins.cloudron",
"title": "Jenkins",
"author": "Cloudron Packager",
"description": "Jenkins is an open source automation server which enables developers to reliably build, test, and deploy their software.",
"tagline": "The leading open source automation server",
"version": "1.0.0",
"healthCheckPath": "/login",
"httpPort": 8080,
"manifestVersion": 2,
"website": "https://jenkins.io/",
"contactEmail": "support@cloudron.io",
"icon": "file://logo.png",
"dockerImage": "cloudron/jenkins",
"memoryLimit": 2048000000,
"addons": {
"localstorage": {
"title": "Jenkins Data"
}
},
"optionalAddons": {
"ldap": {
"title": "LDAP Integration",
"description": "Allow users to login with LDAP credentials"
},
"oauth": {
"title": "OAuth Integration",
"description": "Allow users to login with Cloudron credentials"
}
},
"tags": [
"ci",
"cd",
"devops",
"automation"
],
"postInstallMessage": "Jenkins is now installed. The initial admin password is shown in the logs. You can view it by running 'cloudron logs -f'. The password is displayed after 'Jenkins initial setup is required.' in the logs.",
"minBoxVersion": "5.4.0",
"documentationUrl": "https://jenkins.io/doc/"
}

View File

@@ -0,0 +1,49 @@
FROM cloudron/base:4.2.0
# Add Jenkins repository key and repository
RUN apt-get update && \
apt-get install -y gnupg curl software-properties-common && \
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | gpg --dearmor -o /usr/share/keyrings/jenkins-keyring.gpg && \
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.gpg] https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list
# Install Jenkins and required dependencies
RUN apt-get update && \
apt-get install -y openjdk-17-jdk jenkins fontconfig && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Install required plugins for Cloudron integration
RUN mkdir -p /tmp/data/plugins && \
cd /tmp/data/plugins && \
curl -L -o ldap.hpi https://updates.jenkins.io/latest/ldap.hpi && \
curl -L -o oic-auth.hpi https://updates.jenkins.io/latest/oic-auth.hpi && \
curl -L -o configuration-as-code.hpi https://updates.jenkins.io/latest/configuration-as-code.hpi && \
curl -L -o credentials.hpi https://updates.jenkins.io/latest/credentials.hpi && \
chmod 644 *.hpi
# Create template for casc.yaml
RUN mkdir -p /tmp/data/casc_configs
COPY casc_templates/ /tmp/data/casc_configs/
# Set up directory structure for Cloudron
RUN mkdir -p /app/data && \
mkdir -p /tmp/data/jenkins_home
# Copy startup script
COPY start.sh /app/code/
RUN chmod +x /app/code/start.sh
# Copy NGINX configuration
COPY nginx.conf /app/code/
# Copy supervisor configuration
COPY supervisor.conf /etc/supervisor/conf.d/
# Use the cloudron user for Jenkins
RUN usermod -a -G jenkins cloudron && \
chown -R cloudron:cloudron /tmp/data
WORKDIR /app/data
# Entry point
CMD ["/app/code/start.sh"]

View File

@@ -0,0 +1,97 @@
# Jenkins for Cloudron - Build Notes
This document provides instructions for building, testing, and deploying the Jenkins package to Cloudron.
## Prerequisites
- Cloudron server (version 5.4.0 or higher)
- Docker installed on your build machine
- Cloudron CLI tool installed (`npm install -g cloudron`)
## File Structure
```
jenkins-cloudron/
├── CloudronManifest.json # Package definition
├── Dockerfile # Docker image build instructions
├── start.sh # Initialization script
├── nginx.conf # NGINX configuration
├── supervisor.conf # Supervisor configuration for process management
├── logo.png # App icon (128x128 PNG)
├── casc_templates/ # Jenkins Configuration as Code templates
│ ├── default.yaml # Default authentication config
│ ├── ldap.yaml # LDAP authentication config
│ └── oauth.yaml # OAuth/OIDC authentication config
```
## Building the Package
1. Create a directory for your package and place all files in the appropriate structure.
2. Download a Jenkins logo (128x128 PNG) and save it as `logo.png`
3. Build the Docker image:
```bash
cloudron build
```
4. Test the package locally:
```bash
cloudron install —image cloudron/jenkins
```
## Authentication Configuration
The package supports three authentication methods:
1. **Default (Local)**: Uses Jenkins built-in user database
2. **LDAP**: Uses Cloudrons LDAP server for authentication
3. **OAuth/OIDC**: Uses Cloudrons OAuth service for single sign-on
The authentication method is automatically configured based on the presence of environment variables provided by Cloudron.
## Testing
After installation, test the following:
1. **Basic functionality**:
- Access Jenkins through your Cloudron dashboard
- Verify the initial admin password works
- Create a simple pipeline job
2. **Authentication**:
- Test LDAP integration by enabling the LDAP addon
- Test OAuth/OIDC integration by enabling the OAuth addon
- Verify user permissions are correctly applied
3. **Persistence**:
- Install plugins through the Jenkins UI
- Restart the app to verify plugins persist
- Check that job configurations are maintained
## Troubleshooting
- **Jenkins doesnt start**: Check logs using `cloudron logs -f`
- **Authentication issues**: Verify the correct addons are enabled and configuration is applied
- **Permission problems**: Check the ownership and permissions of files in `/app/data`
## Updating Jenkins
When a new version of Jenkins is released, update the Dockerfile to pull the latest version and rebuild the package.
## Additional Notes
- The package uses Jenkins Configuration as Code (JCasC) to automate the setup process
- Jenkins runs as the `cloudron` user for proper permissions
- Files in `/app/data/jenkins_home` are persisted across restarts and updates
- Initial admin password is set to adminpass for local authentication
## Deployment to Cloudron App Store
If you wish to publish your app to the Cloudron App Store:
1. Update the CloudronManifest.json with your details
2. Test thoroughly on your own Cloudron instance
3. Follow the Cloudron App Publishing guidelines
Happy CI/CD with Jenkins on Cloudron!

View File

@@ -0,0 +1,26 @@
jenkins:
systemMessage: "Jenkins configured with local authentication"
securityRealm:
local:
allowsSignup: false
enableCaptcha: false
users:
- id: "admin"
password: "adminpass"
authorizationStrategy:
globalMatrix:
permissions:
- "Overall/Administer:admin"
- "Overall/Read:authenticated"
- "Job/Read:authenticated"
- "Job/Build:authenticated"
- "Job/Create:authenticated"
- "Job/Configure:authenticated"
- "View/Read:authenticated"
- "View/Create:authenticated"
- "View/Configure:authenticated"
unclassified:
location:
url: "${JENKINS_URL}"

View File

@@ -0,0 +1,32 @@
jenkins:
systemMessage: "Jenkins configured with Cloudron LDAP authentication"
securityRealm:
ldap:
configurations:
- server: "${CLOUDRON_LDAP_SERVER}"
rootDN: "${CLOUDRON_LDAP_USERS_BASE_DN}"
managerDN: "${CLOUDRON_LDAP_BIND_DN}"
managerPasswordSecret: "${CLOUDRON_LDAP_BIND_PASSWORD}"
userSearchBase: ""
userSearch: "uid={0}"
groupSearchBase: "${CLOUDRON_LDAP_GROUPS_BASE_DN}"
groupSearchFilter: "memberUid={0}"
displayNameAttributeName: "displayName"
mailAddressAttributeName: "mail"
authorizationStrategy:
globalMatrix:
permissions:
- "Overall/Administer:admin"
- "Overall/Read:authenticated"
- "Job/Read:authenticated"
- "Job/Build:authenticated"
- "Job/Create:authenticated"
- "Job/Configure:authenticated"
- "View/Read:authenticated"
- "View/Create:authenticated"
- "View/Configure:authenticated"
unclassified:
location:
url: "${JENKINS_URL}"

View File

@@ -0,0 +1,35 @@
jenkins:
systemMessage: "Jenkins configured with Cloudron OpenID Connect authentication"
securityRealm:
oic:
clientId: "${CLOUDRON_OAUTH_CLIENT_ID}"
clientSecret: "${CLOUDRON_OAUTH_CLIENT_SECRET}"
wellKnownOpenIDConfigurationUrl: "${CLOUDRON_OAUTH_ORIGIN}/.well-known/openid-configuration"
userNameField: "preferred_username"
tokenAuthMethod: "client_secret_basic"
scopes: "openid email profile groups"
fullNameFieldName: "name"
emailFieldName: "email"
groupsFieldName: "groups"
pkceEnabled: true
escapeHatchEnabled: true
escapeHatchUsername: "admin"
escapeHatchSecret: "adminpass"
escapeHatchGroup: "admin"
authorizationStrategy:
globalMatrix:
permissions:
- "Overall/Administer:admin"
- "Overall/Read:authenticated"
- "Job/Read:authenticated"
- "Job/Build:authenticated"
- "Job/Create:authenticated"
- "Job/Configure:authenticated"
- "View/Read:authenticated"
- "View/Create:authenticated"
- "View/Configure:authenticated"
unclassified:
location:
url: "${JENKINS_URL}"

View File

@@ -0,0 +1,55 @@
worker_processes 1;
error_log stderr;
pid /run/nginx.pid;
daemon off;
events {
worker_connections 768;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Disable access logs to stdout - Cloudron handles these
access_log off;
server {
listen 8000;
client_max_body_size 50M;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Required for Jenkins websocket connections
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 90;
proxy_redirect http://127.0.0.1:8080 $scheme://$host;
# Fix potential security issues
proxy_cookie_path / "/; HTTPOnly; Secure";
}
# Special config for OIDC callback
location /securityRealm/finishLogin {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}

View File

@@ -0,0 +1,50 @@
#!/bin/bash
set -e
# Jenkins home directory
JENKINS_HOME=/app/data/jenkins_home
# Create necessary directories if they don't exist
if [[ ! -d "${JENKINS_HOME}" ]]; then
echo "Initializing Jenkins home directory"
mkdir -p "${JENKINS_HOME}"
cp -r /tmp/data/jenkins_home/* "${JENKINS_HOME}/" || true
# Copy plugins
mkdir -p "${JENKINS_HOME}/plugins"
cp -r /tmp/data/plugins/* "${JENKINS_HOME}/plugins/" || true
# Create directory for JCasC
mkdir -p "${JENKINS_HOME}/casc_configs"
fi
# Apply proper permissions
chown -R cloudron:cloudron "${JENKINS_HOME}"
# Set up Jenkins environment variables
export JENKINS_HOME
export JENKINS_OPTS="--httpPort=8080"
# Disable setup wizard
export JAVA_OPTS="-Djenkins.install.runSetupWizard=false"
# Setup JCasC configuration based on environment
if [[ -n "${CLOUDRON_OAUTH_CLIENT_ID}" ]]; then
echo "Setting up OAuth authentication"
envsubst < /tmp/data/casc_configs/oauth.yaml > "${JENKINS_HOME}/casc_configs/oauth.yaml"
export CASC_JENKINS_CONFIG="${JENKINS_HOME}/casc_configs/oauth.yaml"
elif [[ -n "${CLOUDRON_LDAP_SERVER}" ]]; then
echo "Setting up LDAP authentication"
envsubst < /tmp/data/casc_configs/ldap.yaml > "${JENKINS_HOME}/casc_configs/ldap.yaml"
export CASC_JENKINS_CONFIG="${JENKINS_HOME}/casc_configs/ldap.yaml"
else
echo "Using default authentication"
envsubst < /tmp/data/casc_configs/default.yaml > "${JENKINS_HOME}/casc_configs/default.yaml"
export CASC_JENKINS_CONFIG="${JENKINS_HOME}/casc_configs/default.yaml"
fi
# Configure Jenkins URL
JENKINS_URL="${CLOUDRON_APP_ORIGIN}"
echo "Setting Jenkins URL to ${JENKINS_URL}"
export JENKINS_URL
# Start supervisord, which will start NGINX and Jenkins
exec /usr/bin/supervisord --nodaemon -c /etc/supervisor/supervisord.conf

View File

@@ -0,0 +1,18 @@
[program:nginx]
command=nginx -c /app/code/nginx.conf
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
[program:jenkins]
command=java -Djava.awt.headless=true -Djenkins.model.Jenkins.slaveAgentPort=50000 -Dhudson.model.UsageStatistics.disabled=true %(ENV_JAVA_OPTS)s -jar /usr/share/java/jenkins.war --httpPort=8080 --webroot=/var/cache/jenkins/war %(ENV_JENKINS_OPTS)s
directory=/app/data/jenkins_home
user=cloudron
environment=HOME="/app/data/jenkins_home",USER="cloudron"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true

View File

@@ -0,0 +1,86 @@
Cloudron Application Packaging Wizard
# Cloudron Application Packaging Wizard
You are a Cloudron packaging expert who will help me package any application for deployment on the Cloudron platform. Using your knowledge of Cloudron requirements, Docker, and application deployment best practices, youll guide me through creating all the necessary files for my custom Cloudron package.
## Your Process
1. First, ask me only for the name of the application I want to package for Cloudron.
2. Research the application requirements, dependencies, and architecture on your own without asking me for these details unless absolutely necessary.
3. Create all required files for packaging:
- CloudronManifest.json
- Dockerfile
- start.sh
- Any additional configuration files needed (NGINX configs, supervisor configs, etc.)
4. Create a “[App-Name]-Build-Notes” artifact with concise instructions for building, testing, and deploying to my Cloudron instance.
## Key Principles to Apply
### CloudronManifest.json
- Create an appropriate app ID following reverse-domain notation
- Set memory limits based on the application requirements
- Configure the proper httpPort which must match your NGINX setup
- Include necessary addons (postgresql, mysql, mongodb, redis, localstorage, etc.)
- Add appropriate metadata (icon, description, author)
- Include a postInstallMessage with initial login credentials if applicable
- Configure authentication options (OIDC or LDAP)
### Authentication Configuration
- Configure the app to use Cloudrons OIDC provider (preferred method):
- Set up routing to `/api/v1/session/callback` in CloudronManifest.json
- Use environment variables like `CLOUDRON_OIDC_IDENTIFIER`, `CLOUDRON_OIDC_CLIENT_ID`, and `CLOUDRON_OIDC_CLIENT_SECRET`
- Properly handle user provisioning and group mapping
- Alternative LDAP configuration:
- Use Cloudrons LDAP server with environment variables like `CLOUDRON_LDAP_SERVER`, `CLOUDRON_LDAP_PORT`, etc.
- Configure proper LDAP bind credentials and user search base
- Map LDAP groups to application roles/permissions
- For apps without native OIDC/LDAP support:
- Implement custom authentication adapters
- Use session management compatible with Cloudrons proxy setup
- Consider implementing an authentication proxy if needed
### Dockerfile
- Use the latest Cloudron base image (cloudron/base:4.2.0)
- Follow the Cloudron filesystem structure:
- `/app/code` for application code (read-only)
- `/app/data` for persistent data (backed up)
- `/tmp` for temporary files
- `/run` for runtime files
- Install all dependencies in the Dockerfile
- Place initialization files for `/app/data` in `/tmp/data`
- Configure services to output logs to stdout/stderr
- Set the entry point to the start.sh script
### start.sh
- Handle initialization of `/app/data` directories from `/tmp/data` if they dont exist
- Configure the application based on Cloudron environment variables (especially for addons)
- Generate secrets/keys on first run
- Set proper permissions (chown cloudron:cloudron)
- Process database migrations or other initialization steps
- Launch the application with supervisor or directly
- Configure authentication providers during startup
### Web Server Configuration
- Configure NGINX to listen on the port specified in CloudronManifest.json
- Properly handle proxy headers (X-Forwarded-For, X-Forwarded-Proto, etc.)
- Configure the application to work behind Cloudrons reverse proxy
- Set up correct paths for static and media files
- Ensure logs are sent to stdout/stderr
- Configure proper authentication routing for OIDC callbacks
### Process Management
- Use supervisord for applications with multiple components
- Configure proper signal handling
- Ensure processes run with the cloudron user where possible
- Set appropriate resource limits
## Best Practices
- Properly separate read-only and writable directories
- Secure sensitive information using environment variables or files in /app/data
- Generate passwords and secrets on first run
- Handle database migrations and schema updates safely
- Ensure the app can update cleanly
- Make configurations adaptable through environment variables
- Include health checks in the CloudronManifest.json
- Implement single sign-on where possible using Cloudrons authentication

107
CloudronPackages/README.md Normal file
View File

@@ -0,0 +1,107 @@
# TSYS Cloudron Packages
This directory contains **finalized, tested packages** ready for deployment to Cloudron. Each package represents a complete application that has been:
-**Developed** using the containerized workflow
-**Tested** with build and basic functionality validation
-**Documented** with comprehensive build notes
-**Validated** through our quality assurance process
## 📋 Package Structure
Each application package contains:
### Required Files
- **`CloudronManifest.json`** - App metadata, resource requirements, addon dependencies
- **`Dockerfile`** - Container build instructions following Cloudron conventions
- **`start.sh`** - Application startup script with proper initialization
- **`[AppName]-BuildNotes.md`** - Complete build and deployment instructions
### Common Optional Files
- **`nginx.conf`** - Web server configuration
- **`supervisord.conf`** - Multi-process management configuration
- **`config.yaml`** - Application-specific configuration template
- **`logo.png`** - Application icon for Cloudron dashboard
## 📦 Available Packages
| Package | Status | Version | Complexity | Notes |
|---------|--------|---------|------------|--------|
| [EasyGate](EasyGate/) | ✅ Complete | 1.0.0 | Low | Simple infrastructure dashboard |
| [PackageTemplate](PackageTemplate/) | 📖 Template | - | - | Template and LLM prompts |
## 🚀 Using These Packages
### Prerequisites
- Docker for building containers
- Cloudron CLI: `npm install -g cloudron`
- Access to container registry for image storage
### Build Process
```bash
cd CloudronPackages/[AppName]/
# Build the container
docker build -t your-registry/[appname]:version .
# Push to registry
docker push your-registry/[appname]:version
# Deploy to Cloudron
cloudron install --image your-registry/[appname]:version
```
### Testing Locally
```bash
# Basic functionality test
docker run --rm -p 8080:8080 your-registry/[appname]:version
# Check logs
docker logs [container-id]
```
## 🔧 Development Process
### From Development to Final Package
1. **Development**: Work in `[appname]_package_new/` using `tsys-cloudron-packaging` container
2. **Testing**: Build and validate package functionality
3. **Finalization**: Move completed package to `CloudronPackages/[AppName]/`
4. **Documentation**: Ensure all required files and build notes are complete
5. **Git Workflow**: Commit via feature branch → integration → main
### Quality Standards
All packages in this directory must meet:
- ✅ Use `cloudron/base:4.2.0` base image
- ✅ Proper Cloudron filesystem structure (`/app/code`, `/app/data`)
- ✅ Integration with Cloudron addons via environment variables
- ✅ Comprehensive health checks and logging to stdout/stderr
- ✅ Security best practices (no hardcoded secrets)
- ✅ Complete and tested build documentation
## 📚 Resources
- **[Development Guide](../README.md)** - Complete development workflow
- **[Package Template](PackageTemplate/)** - Baseline template and LLM prompts
- **[Git Workflow](../GIT_WORKFLOW.md)** - Branching and release process
- **[Task List](../TASKS.md)** - Current packaging priorities
## 🤝 Contributing
### Adding New Packages
1. Follow the development workflow in the main [README](../README.md)
2. Use the feature branch pattern: `feature/package-[appname]`
3. Ensure all quality standards are met
4. Include comprehensive build notes and testing instructions
5. Update the package table above when adding new entries
### Updating Existing Packages
1. Create hotfix branch: `hotfix/[appname]-[issue]`
2. Make minimal necessary changes
3. Test thoroughly before merging
4. Update version numbers and documentation
---
**Maintained By**: KNEL/TSYS Development Team
**Last Updated**: 2025-01-04
**Part of**: [KNEL Production Containers](../README.md) packaging project

View File

@@ -0,0 +1,33 @@
{
"id": "com.rathole.cloudron",
"title": "Rathole",
"author": "Rathole Organization",
"description": "A secure, stable, and high-performance reverse proxy for NAT traversal, written in Rust.",
"tagline": "Secure NAT traversal reverse proxy",
"version": "0.5.0",
"healthCheckPath": "/health",
"httpPort": 8080,
"tcpPorts": {
"2333": "Rathole Server Port"
},
"addons": {
"localstorage": {}
},
"manifestVersion": 2,
"website": "https://github.com/rathole-org/rathole",
"contactEmail": "support@cloudron.io",
"icon": "logo.png",
"tags": [
"proxy",
"networking",
"nat-traversal",
"tunnel"
],
"env": {
"RATHOLE_SERVER_TOKEN": "changeme",
"RATHOLE_SERVER_PORT": "2333"
},
"configurePath": "/",
"minBoxVersion": "7.0.0",
"postInstallMessage": "Rathole has been successfully installed. Configure your server token and port settings as needed. The service listens on TCP port 2333 by default."
}

View File

@@ -0,0 +1,37 @@
FROM cloudron/base:4.2.0
# Install necessary tools
RUN apt-get update && apt-get install -y \
curl \
unzip \
python3 \
--no-install-recommends && \
rm -rf /var/lib/apt/lists/*
# Set up directory structure following Cloudron conventions
RUN mkdir -p /app/code /app/data
# Download and extract Rathole (using a more reliable approach)
RUN cd /tmp && \
curl -L -o rathole.zip https://github.com/rathole-org/rathole/releases/download/v0.5.0/rathole-x86_64-unknown-linux-gnu.zip && \
unzip rathole.zip && \
mv rathole /app/code/ && \
chmod +x /app/code/rathole && \
rm -f rathole.zip
# Copy start script
COPY start.sh /app/code/start.sh
RUN chmod +x /app/code/start.sh
# Set proper permissions
RUN chown -R cloudron:cloudron /app/code /app/data
# Configure working directory and user
WORKDIR /app/code
USER cloudron
# Expose ports
EXPOSE 2333 8080
# Start the application
CMD ["/app/code/start.sh"]

View File

@@ -0,0 +1,157 @@
# Rathole Cloudron Package - Build Notes
## Overview
Rathole is a secure, stable, and high-performance reverse proxy for NAT traversal, written in Rust. This package provides a Cloudron-ready deployment of the Rathole server component.
## Package Details
- **Version**: 0.5.0
- **Architecture**: x86_64-unknown-linux-gnu
- **Base Image**: cloudron/base:4.2.0
- **Ports**: TCP 2333 (Rathole server), HTTP 8080 (health check)
## Build Process
### Prerequisites
- Docker
- Cloudron CLI (`npm install -g cloudron`)
- Access to upstream Rathole releases
### Build Steps
```bash
# Navigate to package directory
cd CloudronPackages/Rathole
# Build the Docker image
docker build -t rathole:latest .
# Test locally (optional)
docker run -d --name rathole-test \
-p 2333:2333 \
-p 8080:8080 \
-e RATHOLE_SERVER_TOKEN=test-token \
rathole:latest
# Check logs
docker logs rathole-test
# Clean up test container
docker stop rathole-test && docker rm rathole-test
```
## Configuration
### Environment Variables
- `RATHOLE_SERVER_TOKEN`: Mandatory service token for authentication (default: "changeme")
- `RATHOLE_SERVER_PORT`: Server listening port (default: "2333")
### Generated Configuration
The package automatically generates `/app/data/rathole.toml` with the following structure:
```toml
[server]
bind_addr = "0.0.0.0:2333"
token = "your-token-here"
```
## Cloudron Integration
### Addons
- **localstorage**: For persistent configuration storage
### Health Checks
- HTTP health check endpoint at `http://localhost:8080/health`
- Returns "OK" when the service is running
### Networking
- TCP port 2333: Rathole server port (exposed to external clients)
- HTTP port 8080: Internal health check port
## Deployment
### Install Command
```bash
cloudron install --image rathole:latest
```
### Post-Installation
1. Configure the server token in the Cloudron environment variables
2. Update the port if needed (default: 2333)
3. Configure client connections to point to the Cloudron instance
## Client Configuration Example
For Rathole clients to connect to this server:
```toml
[client]
remote_addr = "your-cloudron-domain.com:2333"
token = "your-server-token"
[client.services.your-service]
local_addr = "127.0.0.1:8080"
remote_addr = "0.0.0.0:8080"
```
## Troubleshooting
### Common Issues
1. **Connection Refused on Port 2333**
- Check if the container is running: `docker ps`
- Verify the server token matches between client and server
- Check Cloudron firewall settings
2. **Health Check Failing**
- Verify the health check server is running on port 8080
- Check container logs: `docker logs <container-id>`
3. **Configuration Not Persisting**
- Ensure `/app/data` is properly mounted
- Check file permissions (should be owned by cloudron user)
### Debug Commands
```bash
# Check container status
docker ps | grep rathole
# View logs
docker logs <container-id>
# Enter container for debugging
docker exec -it <container-id> /bin/bash
# Test connectivity
telnet your-cloudron-domain.com 2333
```
## Security Considerations
1. **Token Security**: Use a strong, unique token for production
2. **Network Access**: Only expose port 2333 to trusted clients
3. **Firewall Rules**: Configure Cloudron firewall to restrict access to authorized IPs
## Performance Tuning
- Default configuration should work for most use cases
- For high-throughput scenarios, consider adjusting system limits
- Monitor resource usage through Cloudron dashboard
## Version Updates
To update to a newer version of Rathole:
1. Update the `RATHOLE_VERSION` ARG in the Dockerfile
2. Rebuild the Docker image
3. Test thoroughly before deploying to production
4. Update this documentation with any new configuration options
## Support
- **Rathole Documentation**: https://github.com/rathole-org/rathole
- **Cloudron Documentation**: https://docs.cloudron.io
- **Package Issues**: Report via KNEL's issue tracking system
---
**Build Date**: 2025-01-04
**Builder**: KNEL/TSYS Development Team
**Tested On**: Cloudron 7.0.0+

View File

@@ -0,0 +1,45 @@
#!/bin/bash
set -euo pipefail
# Set default values
: ${RATHOLE_SERVER_PORT:=2333}
: ${RATHOLE_SERVER_TOKEN:=changeme}
# Generate rathole.toml configuration file with correct format
cat <<EOF > /app/data/rathole.toml
[server]
bind_addr = "0.0.0.0:$RATHOLE_SERVER_PORT"
default_token = "$RATHOLE_SERVER_TOKEN"
[server.services]
EOF
echo "Starting Rathole server on port $RATHOLE_SERVER_PORT with token: ${RATHOLE_SERVER_TOKEN:0:8}..."
# Start Rathole server in background
/app/code/rathole --server /app/data/rathole.toml &
# Wait a moment for Rathole to start
sleep 2
# Check if Rathole started successfully
if pgrep -f rathole > /dev/null; then
echo "Rathole server started successfully"
# Create a simple health check file
mkdir -p /tmp/health
echo "OK" > /tmp/health/index.html
# Start a simple HTTP server for health checks on port 8080
cd /tmp/health
python3 -m http.server 8080 &
echo "Health check server started on port 8080"
# Keep the script running to maintain the container
wait
else
echo "Failed to start Rathole server"
exit 1
fi

View File

@@ -0,0 +1,62 @@
{
"id": "com.resgrid.cloudron",
"version": "1.0.0",
"author": "Your Name <your.email@example.com>",
"title": "Resgrid",
"description": "Open Source Computer Aided Dispatch (CAD), Personnel, Shift Management, Automatic Vehicle Location (AVL) and Emergency Management Platform",
"tagline": "Dispatch solution for first responders, business and industry",
"website": "https://resgrid.com/",
"contactEmail": "your.email@example.com",
"icon": "/logo.png",
"tags": [
"dispatch",
"emergency",
"management",
"first-responders"
],
"httpPort": 8000,
"manifestVersion": 2,
"healthCheckPath": "/",
"memoryLimit": 1024,
"documentationUrl": "https://resgrid-core.readthedocs.io/en/latest/",
"addons": {
"localstorage": {},
"redis": {},
"postgresql": {},
"sendmail": {}
},
"tcpPorts": {
"rabbitmq": {
"title": "RabbitMQ",
"description": "Port for RabbitMQ message queue service",
"containerPort": 5672
}
},
"postInstallMessage": "Resgrid has been successfully installed. The default administrator account is 'admin' with password 'changeme'. Please change this password immediately after the first login.",
"minBoxVersion": "5.4.0",
"forwardedPorts": [],
"configurePath": "/settings",
"env": {
"RESGRID_CLOUDRON": "true",
"RESGRID_DB_TYPE": "postgresql",
"POSTGRES_HOST": "{{ postgresql.host }}",
"POSTGRES_PORT": "{{ postgresql.port }}",
"POSTGRES_USERNAME": "{{ postgresql.username }}",
"POSTGRES_PASSWORD": "{{ postgresql.password }}",
"POSTGRES_DATABASE": "{{ postgresql.database }}",
"REDIS_HOST": "{{ redis.host }}",
"REDIS_PORT": "{{ redis.port }}",
"REDIS_PASSWORD": "{{ redis.password }}",
"CLOUDRON_APP_DOMAIN": "{{ appDomain }}",
"CLOUDRON_MAIL_SMTP_SERVER": "{{ mail.smtp.hostname }}",
"CLOUDRON_MAIL_SMTP_PORT": "{{ mail.smtp.port }}",
"CLOUDRON_MAIL_SMTP_USERNAME": "{{ mail.smtp.username }}",
"CLOUDRON_MAIL_SMTP_PASSWORD": "{{ mail.smtp.password }}",
"CLOUDRON_MAIL_FROM": "{{ mail.from }}",
"CLOUDRON_OIDC_IDENTIFIER": "{{ oauth.clientId }}",
"CLOUDRON_OIDC_CLIENT_ID": "{{ oauth.clientId }}",
"CLOUDRON_OIDC_CLIENT_SECRET": "{{ oauth.clientSecret }}",
"CLOUDRON_OIDC_ISSUER": "{{ oauth.issuer }}",
"CLOUDRON_OIDC_ORIGIN": "{{ origin }}"
}
}

View File

@@ -0,0 +1,75 @@
FROM cloudron/base:4.2.0
# Environment variables
ENV RESGRID_VERSION="0.5.30" \
DEBIAN_FRONTEND="noninteractive" \
DOTNET_RUNNING_IN_CONTAINER=true \
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false \
LC_ALL=en_US.UTF-8 \
LANG=en_US.UTF-8
# Install dependencies
RUN apt-get update && apt-get install -y \
curl \
wget \
gnupg2 \
apt-transport-https \
software-properties-common \
supervisor \
nginx \
vim \
unzip \
gettext-base \
netcat-openbsd \
locales \
&& locale-gen en_US.UTF-8 \
&& rm -rf /var/lib/apt/lists/*
# Install .NET Core
RUN curl -SL --output packages-microsoft-prod.deb https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb \
&& dpkg -i packages-microsoft-prod.deb \
&& apt-get update \
&& apt-get install -y dotnet-sdk-6.0 \
&& rm -f packages-microsoft-prod.deb \
&& rm -rf /var/lib/apt/lists/*
# Download and extract Resgrid Docker setup files
WORKDIR /tmp
RUN wget -q https://github.com/Resgrid/Core/releases/download/v${RESGRID_VERSION}/resgrid.tgz \
&& mkdir -p /tmp/resgrid \
&& tar -xzf resgrid.tgz -C /tmp/resgrid \
&& rm resgrid.tgz
# Create directory structure
RUN mkdir -p /app/code \
&& mkdir -p /app/data/config \
&& mkdir -p /app/data/logs \
&& mkdir -p /app/data/uploads \
&& mkdir -p /app/data/backup
# Copy Resgrid components to the code directory
WORKDIR /app/code
# Setup configuration directory for first run
RUN mkdir -p /tmp/data/config
# Copy configuration files and setup scripts to temporary directory
COPY start.sh /app/code/
COPY nginx.conf /app/code/
COPY supervisord.conf /app/code/
COPY resgrid.env.template /app/code/
# Make start script executable
RUN chmod +x /app/code/start.sh
# Ensure all files have the correct permissions
RUN chown -R cloudron:cloudron /app
# Switch to the cloudron user
USER cloudron
# Expose the port defined in CloudronManifest.json
EXPOSE 8000
# Set the entrypoint to the start script
ENTRYPOINT ["/app/code/start.sh"]

View File

@@ -0,0 +1,137 @@
# Resgrid Cloudron Package Build Notes
This document provides instructions for building, testing, and deploying the Resgrid Cloudron package.
## Package Overview
Resgrid is an open-source Computer Aided Dispatch (CAD), Personnel, Shift Management, Automatic Vehicle Location (AVL), and Emergency Management Platform. This Cloudron package installs Resgrid with the following components:
- Resgrid Web Core (user interface)
- Resgrid Web Services (API backend)
- Resgrid Workers Console (background processing)
- Resgrid Events Service (real-time notifications using SignalR)
## Prerequisites
- Cloudron server (version 7.2.0 or higher)
- Docker installed on your build machine
- Git installed on your build machine
- About 2GB+ of RAM available on your Cloudron server
- MySQL, Redis, and RabbitMQ addons available on your Cloudron server
## Build Instructions
1. Clone the repository to your local machine:
```bash
git clone https://github.com/yourusername/cloudron-resgrid.git
cd cloudron-resgrid
```
2. Download the Resgrid logo and save it as `logo.png` in the package directory:
```bash
curl -o logo.png https://resgrid.com/images/logo.png
```
3. Build the Cloudron package:
```bash
cloudron build
```
4. If successful, the package file will be created in the current directory with a `.tar.gz` extension.
## Deployment Instructions
### Method 1: Direct Installation from Package
1. Install the package on your Cloudron server:
```bash
cloudron install —image resgrid.tar.gz
```
2. Follow the on-screen instructions to complete the installation.
### Method 2: Using the Cloudron App Store (if published)
1. Log into your Cloudron dashboard
2. Go to App Store
3. Search for “Resgrid”
4. Click “Install”
5. Follow the on-screen instructions
## Post-Installation Configuration
After installation, you should:
1. Log in with the default admin credentials:
- Username: admin@example.com
- Password: (Auto-generated, check Cloudron post-install message)
2. Change the default admin password
3. Configure your department settings:
- Set the department name
- Configure time zone
- Set up groups and roles
4. If using Cloudron SSO (recommended):
- The app is already configured to use Cloudrons OIDC provider
- Users who log in via SSO will be created in Resgrid automatically
- Youll need to assign appropriate roles to these users in the Resgrid admin interface
## Troubleshooting
### Database Connection Issues
If you encounter database connection issues:
1. Check the logs via the Cloudron dashboard
2. Verify the MySQL addon is running
3. Ensure the database credentials are correctly configured
### Redis or RabbitMQ Issues
1. Check the logs for connection errors
2. Verify the addons are running
3. Restart the app if necessary: `cloudron restart —app resgrid.yourdomain.com`
### Container Startup Problems
If one or more containers fail to start:
1. SSH into the app: `cloudron exec —app resgrid.yourdomain.com`
2. Check Docker container status: `docker ps -a | grep resgrid`
3. View container logs: `docker logs resgrid-web` (or replace with the problematic container name)
## Backup and Restore
The Cloudron platform automatically backs up all Resgrid data stored in:
- MySQL database (via the MySQL addon)
- Redis (via the Redis addon)
- RabbitMQ (via the RabbitMQ addon)
- Local files in `/app/data` (file uploads, configuration, etc.)
To manually create a backup:
```bash
cloudron backup create —app resgrid.yourdomain.com
```
To restore from a backup:
```bash
cloudron restore —app resgrid.yourdomain.com —backup backup_id
```
## Updating
When a new version of the Resgrid Cloudron package is available:
1. Download the new package version
2. Update your existing installation:
```bash
cloudron update —app resgrid.yourdomain.com —image new-resgrid.tar.gz
```
## Additional Resources
- [Resgrid Documentation](https://resgrid-core.readthedocs.io/)
- [Cloudron Documentation](https://docs.cloudron.io/)
- [Resgrid GitHub Repository](https://github.com/Resgrid/Core)

View File

@@ -0,0 +1,66 @@
server {
listen 8000;
server_name _;
access_log /dev/stdout;
error_log /dev/stderr;
client_max_body_size 100M;
# Web application
location / {
proxy_pass http://localhost:8002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_read_timeout 90;
}
# API endpoints
location /api/ {
proxy_pass http://localhost:8001/api/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300;
}
# Events/SignalR endpoint
location /events/ {
proxy_pass http://localhost:8003/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300;
}
# OIDC callback - required for Cloudron authentication
location /api/v1/session/callback {
proxy_pass http://localhost:8001/api/v1/session/callback;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Static files & uploads
location /uploads/ {
alias /app/data/uploads/;
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}
}

View File

@@ -0,0 +1,66 @@
# Core Resgrid settings
RESGRID__ApiUrl=${RESGRID_API_URL}
RESGRID__BaseUrl=${RESGRID_BASE_URL}
RESGRID__EventsUrl=${RESGRID_EVENTS_URL}
RESGRID__PublicEventsUrl=${RESGRID_EVENTS_URL}
RESGRID__AdminEmailAddress=admin@example.com
RESGRID__AdminPassword=${RESGRID_ADMIN_PASSWORD}
RESGRID__ApiKey=${RESGRID_API_KEY}
# Database connection
RESGRID__DataConfig__Provider=sqlserver
RESGRID__DataConfig__Server=${RESGRID_DB_HOST}
RESGRID__DataConfig__Port=${RESGRID_DB_PORT}
RESGRID__DataConfig__Database=${RESGRID_DB_NAME}
RESGRID__DataConfig__UserName=${RESGRID_DB_USER}
RESGRID__DataConfig__Password=${RESGRID_DB_PASSWORD}
RESGRID__DataConfig__CommandTimeout=300
RESGRID__DataConfig__ConnectionTimeout=30
# Redis connection
RESGRID__Caching__RedisConnectionString=redis://:${RESGRID_REDIS_PASSWORD}@${RESGRID_REDIS_HOST}:${RESGRID_REDIS_PORT}
RESGRID__Caching__Provider=redis
# RabbitMQ connection
RESGRID__ServiceBusConfig__Provider=rabbitmq
RESGRID__ServiceBusConfig__Server=${RESGRID_RABBITMQ_HOST}
RESGRID__ServiceBusConfig__Port=${RESGRID_RABBITMQ_PORT}
RESGRID__ServiceBusConfig__Username=${RESGRID_RABBITMQ_USER}
RESGRID__ServiceBusConfig__Password=${RESGRID_RABBITMQ_PASSWORD}
RESGRID__ServiceBusConfig__VirtualHost=${RESGRID_RABBITMQ_VHOST}
# Security settings
RESGRID__Security__EnableSsl=true
RESGRID__Security__RequireSSL=true
RESGRID__Security__AllowLocalReg=false
RESGRID__Security__DisableSignalR=false
# OIDC configuration
RESGRID__Security__OIDC__Enabled=${RESGRID_OIDC_ENABLED}
RESGRID__Security__OIDC__ClientId=${RESGRID_OIDC_CLIENT_ID}
RESGRID__Security__OIDC__ClientSecret=${RESGRID_OIDC_CLIENT_SECRET}
RESGRID__Security__OIDC__Authority=${RESGRID_OIDC_AUTHORITY}
RESGRID__Security__OIDC__CallbackPath=${RESGRID_OIDC_CALLBACK_PATH}
RESGRID__Security__OIDC__ResponseType=code
RESGRID__Security__OIDC__GetClaimsFromUserInfoEndpoint=true
RESGRID__Security__OIDC__RequireHttpsMetadata=true
RESGRID__Security__OIDC__SaveTokens=true
# Email settings
RESGRID__EmailConfig__Provider=smtp
RESGRID__EmailConfig__Server=localhost
RESGRID__EmailConfig__Port=25
RESGRID__EmailConfig__FromEmail=no-reply@example.com
RESGRID__EmailConfig__FromName=Resgrid System
RESGRID__EmailConfig__Username=
RESGRID__EmailConfig__Password=
RESGRID__EmailConfig__EnableSsl=false
# File storage
RESGRID__FileStorage__Provider=localstorage
RESGRID__FileStorage__LocalStoragePath=/app/data/uploads
# Logging
RESGRID__Logging__LogLevel=Information
RESGRID__Logging__Provider=file
RESGRID__Logging__FilePath=/app/data/logs

View File

@@ -0,0 +1,141 @@
#!/bin/bash
set -e
# Function for logging
log() {
echo "$(date +"%Y-%m-%d %H:%M:%S"): $1"
}
log "Starting Resgrid Cloudron App..."
# Initialize data directory if it's the first run
if [ ! -f /app/data/config/.initialized ]; then
log "First run detected, initializing data directory..."
# Copy initial configuration files if they don't exist
if [ ! -f /app/data/config/resgrid.env ]; then
log "Creating initial configuration..."
# Generate random keys and passwords
ADMIN_PASSWORD=$(openssl rand -base64 12)
DB_PASSWORD=${CLOUDRON_MYSQL_PASSWORD}
API_KEY=$(openssl rand -hex 32)
# Create environment configuration from template
export RESGRID_ADMIN_PASSWORD=$ADMIN_PASSWORD
export RESGRID_DB_PASSWORD=$DB_PASSWORD
export RESGRID_API_KEY=$API_KEY
export RESGRID_DB_HOST=${CLOUDRON_MYSQL_HOST}
export RESGRID_DB_PORT=${CLOUDRON_MYSQL_PORT}
export RESGRID_DB_USER=${CLOUDRON_MYSQL_USERNAME}
export RESGRID_DB_NAME=${CLOUDRON_MYSQL_DATABASE}
export RESGRID_REDIS_HOST=${CLOUDRON_REDIS_HOST}
export RESGRID_REDIS_PORT=${CLOUDRON_REDIS_PORT}
export RESGRID_REDIS_PASSWORD=${CLOUDRON_REDIS_PASSWORD}
export RESGRID_RABBITMQ_HOST=${CLOUDRON_RABBITMQ_HOST}
export RESGRID_RABBITMQ_PORT=${CLOUDRON_RABBITMQ_PORT}
export RESGRID_RABBITMQ_USER=${CLOUDRON_RABBITMQ_USERNAME}
export RESGRID_RABBITMQ_PASSWORD=${CLOUDRON_RABBITMQ_PASSWORD}
export RESGRID_RABBITMQ_VHOST=${CLOUDRON_RABBITMQ_VHOST}
export RESGRID_BASE_URL="https://${CLOUDRON_APP_DOMAIN}"
export RESGRID_API_URL="https://${CLOUDRON_APP_DOMAIN}/api"
export RESGRID_EVENTS_URL="https://${CLOUDRON_APP_DOMAIN}/events"
# OIDC Configuration for Cloudron
export RESGRID_OIDC_ENABLED="true"
export RESGRID_OIDC_CLIENT_ID=${CLOUDRON_OIDC_CLIENT_ID}
export RESGRID_OIDC_CLIENT_SECRET=${CLOUDRON_OIDC_CLIENT_SECRET}
export RESGRID_OIDC_AUTHORITY=${CLOUDRON_OIDC_ISSUER}
export RESGRID_OIDC_CALLBACK_PATH="/api/v1/session/callback"
# Process the template
envsubst < /app/code/resgrid.env.template > /app/data/config/resgrid.env
log "Initial configuration created successfully."
fi
# Mark as initialized
touch /app/data/config/.initialized
log "Initialization completed successfully."
fi
# Link configuration files to expected locations
ln -sf /app/data/config/resgrid.env /app/code/resgrid.env
ln -sf /app/code/nginx.conf /etc/nginx/sites-available/default
# Ensure uploads directory exists with correct permissions
mkdir -p /app/data/uploads
chmod 755 /app/data/uploads
# Wait for database to be ready
log "Waiting for MySQL database to be ready..."
until nc -z ${CLOUDRON_MYSQL_HOST} ${CLOUDRON_MYSQL_PORT}; do
log "MySQL is unavailable - sleeping for 5 seconds"
sleep 5
done
log "MySQL is available, continuing..."
# Wait for Redis to be ready
log "Waiting for Redis to be ready..."
until nc -z ${CLOUDRON_REDIS_HOST} ${CLOUDRON_REDIS_PORT}; do
log "Redis is unavailable - sleeping for 5 seconds"
sleep 5
done
log "Redis is available, continuing..."
# Wait for RabbitMQ to be ready
log "Waiting for RabbitMQ to be ready..."
until nc -z ${CLOUDRON_RABBITMQ_HOST} ${CLOUDRON_RABBITMQ_PORT}; do
log "RabbitMQ is unavailable - sleeping for 5 seconds"
sleep 5
done
log "RabbitMQ is available, continuing..."
# Pull Resgrid Docker images
log "Pulling Resgrid Docker images..."
docker pull resgridllc/resgridwebcore:${RESGRID_VERSION}
docker pull resgridllc/resgridwebservices:${RESGRID_VERSION}
docker pull resgridllc/resgridworkersconsole:${RESGRID_VERSION}
docker pull resgridllc/resgridwebevents:${RESGRID_VERSION}
# Create Docker network if it doesn't exist
docker network create resgrid-network 2>/dev/null || true
# Run the containers with environment variables from the config file
log "Starting Resgrid containers..."
source /app/data/config/resgrid.env
# Start API Service
docker run -d --name resgrid-api \
--restart unless-stopped \
--network resgrid-network \
-p 8001:80 \
--env-file /app/data/config/resgrid.env \
resgridllc/resgridwebservices:${RESGRID_VERSION}
# Start Web Core
docker run -d --name resgrid-web \
--restart unless-stopped \
--network resgrid-network \
-p 8002:80 \
--env-file /app/data/config/resgrid.env \
resgridllc/resgridwebcore:${RESGRID_VERSION}
# Start Events Service
docker run -d --name resgrid-events \
--restart unless-stopped \
--network resgrid-network \
-p 8003:80 \
--env-file /app/data/config/resgrid.env \
resgridllc/resgridwebevents:${RESGRID_VERSION}
# Start Workers Console
docker run -d --name resgrid-workers \
--restart unless-stopped \
--network resgrid-network \
--env-file /app/data/config/resgrid.env \
resgridllc/resgridworkersconsole:${RESGRID_VERSION}
# Start supervisord to manage Nginx and other processes
log "Starting supervisord..."
exec /usr/bin/supervisord -c /app/code/supervisord.conf

View File

@@ -0,0 +1,24 @@
[supervisord]
nodaemon=true
logfile=/dev/stdout
logfile_maxbytes=0
pidfile=/var/run/supervisord.pid
user=root
[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:docker-containers-monitor]
command=/bin/bash -c "while true; do docker ps -a | grep -E 'resgrid-(api|web|events|workers)' | grep -v running > /dev/null && for c in resgrid-api resgrid-web resgrid-events resgrid-workers; do docker start $c 2>/dev/null || true; done; sleep 60; done"
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View File

@@ -0,0 +1,43 @@
{
"id": "org.reviewboard.cloudron",
"title": "ReviewBoard",
"author": "Beanbag, Inc.",
"description": "ReviewBoard is a web-based code review tool that helps projects and companies keep their code quality high and their bug count low.",
"tagline": "A powerful web-based code review tool",
"version": "1.0.0",
"healthCheckPath": "/",
"httpPort": 8000,
"manifestVersion": 2,
"website": "https://www.reviewboard.org",
"documentationUrl": "https://www.reviewboard.org/docs/",
"contactEmail": "support@cloudron.io",
"icon": "file://logo.png",
"tags": [
"developer",
"code-review",
"collaboration"
],
"memoryLimit": 768,
"addons": {
"localstorage": {},
"postgresql": {
"version": "14"
},
"oidc": {
"loginRedirectUri": "/api/v1/session/callback",
"logoutRedirectUri": "/home",
"tokenSignatureAlgorithm": "RS256"
}
},
"minBoxVersion": "7.0.0",
"postInstallMessage": "The initial admin account is created automatically using your Cloudron credentials. Please open the app to complete the setup process.",
"installationProgress": {
"message": "Installing ReviewBoard. This might take a few minutes...",
"steps": [
{ "id": "download", "title": "Downloading" },
{ "id": "install", "title": "Installing Dependencies" },
{ "id": "setup", "title": "Setting up ReviewBoard" },
{ "id": "configure", "title": "Configuring for Cloudron" }
]
}
}

View File

@@ -0,0 +1,44 @@
FROM cloudron/base:4.2.0
# Install required packages
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
python3 python3-pip python3-dev python3-venv \
nginx supervisor \
memcached libpq-dev \
libldap2-dev libsasl2-dev \
git-core subversion \
libxml2-dev libxslt1-dev \
libmagic-dev \
gcc && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Create Python virtual environment
RUN python3 -m venv /app/code/venv
ENV PATH="/app/code/venv/bin:${PATH}"
# Install Review Board dependencies
RUN pip3 install --no-cache-dir --upgrade pip wheel setuptools && \
pip3 install --no-cache-dir psycopg2-binary gunicorn django-storages
# Install Review Board
RUN pip3 install --no-cache-dir reviewboard
# Install OIDC authentication
RUN pip3 install --no-cache-dir mozilla-django-oidc
# Install LDAP authentication
RUN pip3 install --no-cache-dir django-auth-ldap
# Make the data directories ready
RUN mkdir -p /app/data/media /app/data/static /app/data/logs /app/data/conf /app/data/site
# Copy configuration files
COPY nginx.conf /etc/nginx/sites-available/default
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY start.sh /app/code/start.sh
RUN chmod +x /app/code/start.sh
# Set up the entry point
CMD ["/app/code/start.sh"]

View File

@@ -0,0 +1,147 @@
# Review Board - Cloudron Build Notes
This document provides instructions for building, testing, and deploying the Review Board Cloudron package.
## Package Overview
Review Board is a powerful web-based code review tool that helps teams review code, documents, and images before they are committed. This package configures Review Board to run on Cloudron with the following features:
- PostgreSQL database for data storage
- Memcached for caching
- Nginx as the web server
- Gunicorn as the WSGI server
- Support for Cloudrons OIDC and LDAP authentication
- Proper data separation following Cloudrons filesystem layout
## Prerequisites
1. Cloudron CLI tool installed (`npm install -g cloudron`)
2. Docker installed and running
3. Cloudron account with administrative access
## Files Included in the Package
1. **CloudronManifest.json** - Defines the application for Cloudron
2. **Dockerfile** - Instructions for building the Docker image
3. **start.sh** - Initialization and startup script
4. **supervisord.conf** - Process management configuration
5. **nginx.conf** - Web server configuration
## Building the Package
1. Create a new directory for your package files:
```bash
mkdir reviewboard-cloudron
cd reviewboard-cloudron
```
2. Create all the package files in this directory.
3. Download the Review Board icon and save it as `icon.png`:
```bash
curl -L “https://raw.githubusercontent.com/reviewboard/reviewboard/master/reviewboard/static/rb/images/logo.png” -o icon.png
```
4. Build the package:
```bash
cloudron build
```
## Testing Locally (Optional)
1. Run the Docker image locally to test basic functionality:
```bash
docker run -p 8000:8000 cloudron/reviewboard-app:1.0.0
```
2. Access the application at http://localhost:8000 to check if it starts correctly.
## Deploying to Cloudron
1. Install the package on your Cloudron:
```bash
cloudron install —image cloudron/reviewboard-app:1.0.0
```
2. Or, to update an existing installation:
```bash
cloudron update —image cloudron/reviewboard-app:1.0.0 —app reviewboard.yourdomain.com
```
## Post-Installation
1. Access your Review Board instance at the URL assigned by Cloudron.
2. Log in using the initial admin credentials:
- Username: `admin`
- Password: Check the file `/app/data/admin_password.txt` inside the app container:
```bash
cloudron exec —app reviewboard.yourdomain.com cat /app/data/admin_password.txt
```
3. Configure your repository connections in the Review Board admin interface at `/admin/`.
## Authentication Details
### OIDC Authentication (Default)
The package is configured to use Cloudrons OIDC provider when available. Users logging in via OIDC will be automatically provisioned in Review Board.
### LDAP Authentication (Alternative)
If OIDC is not available, the package will fall back to using Cloudrons LDAP server for authentication.
## Repository Support
Review Board supports the following repository types:
- Git
- SVN
- Mercurial
- Perforce
- Bazaar
- CVS
- IBM Rational ClearCase
- And more
Configure these in the Admin > Repositories section after login.
## Troubleshooting
1. Check application logs:
```bash
cloudron logs —app reviewboard.yourdomain.com
```
2. Access the container directly to troubleshoot:
```bash
cloudron exec —app reviewboard.yourdomain.com bash
```
3. Validate database connectivity:
```bash
cloudron exec —app reviewboard.yourdomain.com psql “$CLOUDRON_POSTGRESQL_URL”
```
4. If Review Board shows errors about missing repositories, ensure they are accessible from the Cloudron container.
## Backup and Restore
Cloudron automatically backs up the `/app/data` directory, which includes:
- Database (via PostgreSQL addon)
- Media files (uploaded files, screenshots, etc.)
- Configuration files
- Repository cache
No additional backup configuration is necessary.
## Upgrading Review Board
When a new version of Review Board is released:
1. Update the Dockerfile to install the new version
2. Rebuild the Docker image
3. Update the Cloudron app using the `cloudron update` command
## Additional Resources
- [Review Board Documentation](https://www.reviewboard.org/docs/)
- [Cloudron Documentation](https://docs.cloudron.io/)

View File

@@ -0,0 +1,43 @@
server {
listen 8000;
server_name CLOUDRON_APP_DOMAIN;
client_max_body_size 100M;
# Handle static and media files
location /static/ {
alias /app/data/static/;
expires 30d;
}
location /media/ {
alias /app/data/media/;
expires 30d;
}
# Forward requests to the Django application
location / {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 300s;
proxy_read_timeout 300s;
}
# Set up OIDC callback path
location /api/v1/session/callback {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Handle errors
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

View File

@@ -0,0 +1,187 @@
#!/bin/bash
set -e
# Create data directories if they don't exist
if [ ! -f /app/data/.initialized ]; then
echo "Initializing Review Board data directories..."
# Create directories
mkdir -p /app/data/conf
mkdir -p /app/data/media
mkdir -p /app/data/static
mkdir -p /app/data/logs
# Generate a random admin password and save it
ADMIN_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16)
echo $ADMIN_PASSWORD > /app/data/admin_password.txt
chmod 640 /app/data/admin_password.txt
# Mark as initialized
touch /app/data/.initialized
echo "Initialization complete."
fi
# Set proper ownership
chown -R cloudron:cloudron /app/data
# Configure database connection
if [ ! -f /app/data/conf/settings_local.py ]; then
echo "Creating Review Board configuration..."
# Get database connection details from CLOUDRON_POSTGRESQL_URL
DB_HOST=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d@ -f2 | cut -d/ -f1)
DB_NAME=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d/ -f4)
DB_USER=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d/ -f3 | cut -d: -f1)
DB_PASSWORD=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d: -f3 | cut -d@ -f1)
# Create settings_local.py
cat > /app/data/conf/settings_local.py << EOF
# Cloudron Review Board Settings
import os
# Database settings
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': '${DB_NAME}',
'USER': '${DB_USER}',
'PASSWORD': '${DB_PASSWORD}',
'HOST': '${DB_HOST}',
}
}
# Site settings
SITE_ROOT = '/'
MEDIA_ROOT = '/app/data/media'
STATIC_ROOT = '/app/data/static'
# Email settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'mail'
EMAIL_PORT = 25
DEFAULT_FROM_EMAIL = 'reviewboard@${CLOUDRON_APP_DOMAIN}'
SERVER_EMAIL = 'reviewboard@${CLOUDRON_APP_DOMAIN}'
# Cache settings
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
EOF
# Add authentication settings based on Cloudron's environment
if [ -n "${CLOUDRON_LDAP_SERVER}" ]; then
# LDAP Authentication
cat >> /app/data/conf/settings_local.py << EOF
# LDAP Authentication
AUTHENTICATION_BACKENDS = (
'django_auth_ldap.backend.LDAPBackend',
'django.contrib.auth.backends.ModelBackend',
)
import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType
AUTH_LDAP_SERVER_URI = "ldap://${CLOUDRON_LDAP_SERVER}:${CLOUDRON_LDAP_PORT}"
AUTH_LDAP_BIND_DN = "${CLOUDRON_LDAP_BIND_DN}"
AUTH_LDAP_BIND_PASSWORD = "${CLOUDRON_LDAP_BIND_PASSWORD}"
AUTH_LDAP_USER_SEARCH = LDAPSearch(
"${CLOUDRON_LDAP_USERS_BASE_DN}",
ldap.SCOPE_SUBTREE,
"(${CLOUDRON_LDAP_USERNAME_FIELD}=%(user)s)"
)
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
"${CLOUDRON_LDAP_GROUPS_BASE_DN}",
ldap.SCOPE_SUBTREE,
"(objectClass=groupOfNames)"
)
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()
AUTH_LDAP_USER_ATTR_MAP = {
"first_name": "givenName",
"last_name": "sn",
"email": "mail"
}
AUTH_LDAP_ALWAYS_UPDATE_USER = True
EOF
elif [ -n "${CLOUDRON_OIDC_IDENTIFIER}" ]; then
# OIDC Authentication
cat >> /app/data/conf/settings_local.py << EOF
# OIDC Authentication
AUTHENTICATION_BACKENDS = (
'mozilla_django_oidc.auth.OIDCAuthenticationBackend',
'django.contrib.auth.backends.ModelBackend',
)
OIDC_RP_CLIENT_ID = "${CLOUDRON_OIDC_CLIENT_ID}"
OIDC_RP_CLIENT_SECRET = "${CLOUDRON_OIDC_CLIENT_SECRET}"
OIDC_OP_AUTHORIZATION_ENDPOINT = "${CLOUDRON_OIDC_ENDPOINT}/authorize"
OIDC_OP_TOKEN_ENDPOINT = "${CLOUDRON_OIDC_ENDPOINT}/token"
OIDC_OP_USER_ENDPOINT = "${CLOUDRON_OIDC_ENDPOINT}/userinfo"
OIDC_OP_JWKS_ENDPOINT = "${CLOUDRON_OIDC_ENDPOINT}/jwks"
OIDC_AUTHENTICATE_CLASS = 'mozilla_django_oidc.views.OIDCAuthenticationRequestView'
OIDC_CALLBACK_CLASS = 'mozilla_django_oidc.views.OIDCAuthenticationCallbackView'
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'
def oidc_username_transform(username):
return username.split('@')[0]
OIDC_USERNAME_ALGO = oidc_username_transform
EOF
fi
fi
# Initialize the Review Board site if not already done
if [ ! -f /app/data/.db_initialized ]; then
echo "Setting up the Review Board site..."
# Get database connection details
DB_HOST=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d@ -f2 | cut -d/ -f1)
DB_NAME=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d/ -f4)
DB_USER=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d/ -f3 | cut -d: -f1)
DB_PASSWORD=$(echo "${CLOUDRON_POSTGRESQL_URL}" | cut -d: -f3 | cut -d@ -f1)
# Create a site directory for Review Board
rb-site install --noinput \
--domain-name=${CLOUDRON_APP_DOMAIN} \
--site-root=/ \
--static-url=static/ \
--media-url=media/ \
--db-type=postgresql \
--db-name=${DB_NAME} \
--db-user=${DB_USER} \
--db-pass=${DB_PASSWORD} \
--db-host=${DB_HOST} \
--cache-type=memcached \
--cache-info=localhost:11211 \
--web-server-type=wsgi \
--admin-user=admin \
--admin-password=$(cat /app/data/admin_password.txt) \
--admin-email=admin@${CLOUDRON_APP_DOMAIN} \
/app/data/site
# Copy settings_local.py to the site
cp /app/data/conf/settings_local.py /app/data/site/conf/settings_local.py
# Mark as initialized
touch /app/data/.db_initialized
echo "Database initialization complete."
fi
# Collect static files if they don't exist yet
if [ ! -f /app/data/.static_collected ]; then
echo "Collecting static files..."
cd /app/data/site
PYTHONPATH=/app/data/site python /app/data/site/manage.py collectstatic --noinput
touch /app/data/.static_collected
echo "Static files collected."
fi
# Configure NGINX to use the static and media directories
sed -i "s|CLOUDRON_APP_DOMAIN|${CLOUDRON_APP_DOMAIN}|g" /etc/nginx/sites-available/default
# Start services using supervisord
echo "Starting Review Board..."
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf

View File

@@ -0,0 +1,35 @@
[supervisord]
nodaemon=true
logfile=/dev/stdout
logfile_maxbytes=0
user=root
[program:memcached]
command=/usr/bin/memcached -m 64 -p 11211 -u nobody -l 127.0.0.1
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:reviewboard]
command=/app/code/venv/bin/gunicorn --bind 127.0.0.1:8001 --workers 2 --timeout 90 wsgi:application
directory=/app/data/site
user=cloudron
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=HOME="/app/data",PYTHONPATH="/app/data/site"
[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View File

@@ -0,0 +1,53 @@
{
"id": "com.rundeck.cloudron",
"title": "Rundeck",
"author": "Rundeck, Inc.",
"description": "Job scheduler and runbook automation for teams. Rundeck enables self-service operations with policy-based access control, audit trail, and integrations with your existing tools.",
"tagline": "Job scheduling and runbook automation",
"version": "1.0.0",
"healthCheckPath": "/api/40/system/info",
"httpPort": 8080,
"manifestVersion": 2,
"website": "https://www.rundeck.com/",
"contactEmail": "support@rundeck.com",
"icon": "file://logo.png",
"addons": {
"localstorage": {},
"postgresql": {
"version": "14"
}
},
"tags": [
"automation",
"devops",
"scheduler",
"workflow"
],
"minBoxVersion": "7.4.0",
"memoryLimit": 1024,
"documentationUrl": "https://docs.rundeck.com/",
"postInstallMessage": "Rundeck has been installed. The initial admin credentials are:\nUsername: admin\nPassword: {{ .password }}\n\nPlease change this password immediately after login.",
"startCommand": "/app/code/start.sh",
"configurePath": "/login",
"mediaLinks": [],
"changelog": [
{
"versionCode": 1,
"version": "1.0.0",
"releaseDate": "2025-04-21",
"changes": [
"Initial release of Rundeck for Cloudron"
]
}
],
"forumUrl": "https://github.com/cloudron-io/cloudron-app/issues",
"features": {
"ldap": true,
"oauth": {
"callback": "/user/oidclogin",
"clientId": "{{ cloudron.oauth.clientId }}",
"clientSecret": "{{ cloudron.oauth.clientSecret }}",
"scope": "profile email"
}
}
}

View File

@@ -0,0 +1,65 @@
FROM cloudron/base:4.2.0
# Install dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
openjdk-11-jre-headless \
curl \
supervisor \
nginx \
procps \
&& rm -rf /var/lib/apt/lists/*
# Set Environment Variables
ENV RDECK_BASE=/app/data \
RUNDECK_SERVER_DATASTORE_DRIVER="org.postgresql.Driver" \
RUNDECK_GRAILS_URL="https://{{ cloudron_app_domain }}" \
RUNDECK_SERVER_CONTEXTPATH="/" \
RUNDECK_SERVER_FORWARDED=true \
RUNDECK_LOGGING_STRATEGY=CONSOLE \
SERVER_SERVLET_CONTEXT_PATH="/" \
RUNDECK_JAASLOGIN=true \
RUNDECK_SERVER_ADDRESS=127.0.0.1 \
RUNDECK_SERVER_PORT=4440
# Create necessary directories
RUN mkdir -p /app/code /app/data \
/app/data/etc \
/app/data/server/data \
/app/data/var/logs \
/app/data/projects \
/app/data/libext \
/app/data/.ssh \
/tmp/data/etc \
/tmp/data/server/data \
/tmp/data/var/logs \
/tmp/data/projects \
/tmp/data/libext
# Download and install Rundeck
WORKDIR /tmp
RUN curl -Lo rundeck.war "https://repo1.maven.org/maven2/org/rundeck/rundeck/4.17.0/rundeck-4.17.0.war" && \
mkdir -p /app/code/rundeck/webapps && \
mv rundeck.war /app/code/rundeck/webapps/rundeck.war
# Copy configuration files
COPY start.sh /app/code/
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY nginx.conf /etc/nginx/sites-available/rundeck
COPY realm.properties /tmp/data/etc/
COPY framework.properties /tmp/data/etc/
COPY rundeck-config.properties /tmp/data/etc/
COPY jaas-ldap.conf /tmp/data/etc/
COPY jaas-oidc.conf /tmp/data/etc/
# Configure NGINX
RUN rm -f /etc/nginx/sites-enabled/default && \
ln -sf /etc/nginx/sites-available/rundeck /etc/nginx/sites-enabled/rundeck
# Set permissions
RUN chmod +x /app/code/start.sh && \
chown -R cloudron:cloudron /app/code /app/data /tmp/data
WORKDIR /app/code
CMD ["/app/code/start.sh"]

View File

@@ -0,0 +1,101 @@
# Rundeck Cloudron Package Build Notes
## Overview
This package deploys Rundeck, an open-source automation and job scheduling tool, on Cloudron. It uses PostgreSQL for data storage and can be configured to use either Cloudron's LDAP or OIDC for authentication.
## Package Contents
- **CloudronManifest.json**: Defines the app for Cloudron
- **Dockerfile**: Builds the container with Rundeck and dependencies
- **start.sh**: Initializes the app and manages configuration
- **nginx.conf**: Configures web server to proxy requests to Rundeck
- **supervisord.conf**: Manages Rundeck and Nginx processes
- **Configuration files**:
- framework.properties: Core Rundeck configuration
- rundeck-config.properties: Database and server settings
- jaas-ldap.conf: LDAP authentication configuration
- jaas-oidc.conf: OAuth/OIDC authentication configuration
- realm.properties: Default user credentials
## Building the Package
1. Create a new directory for your Cloudron package
2. Place all the files in this package in that directory
3. Download a Rundeck logo and save it as `logo.png` in the package directory
4. Build the package with the Cloudron CLI:
```
cloudron build
```
## Testing
1. Install the package on a test Cloudron instance:
```
cloudron install --image [your-image-name]
```
2. After installation, access the app at its Cloudron URL
3. Log in with the credentials shown in the post-install message
4. Test basic functionality:
- Create a project
- Define a simple job
- Run the job and verify it executes correctly
- Check that logs are saved correctly
5. Test authentication:
- If LDAP is enabled, test login with a Cloudron user
- If OIDC is enabled, test single sign-on functionality
- Verify proper permissions mapping
## Deploying to Production
1. After successful testing, publish the package for your production Cloudron:
```
cloudron install --app rundeck --image [your-image-name]
```
2. Configure backup schedules through the Cloudron UI
3. Update the admin password immediately after installation
4. Configure necessary projects and jobs
## Authentication Configuration
The package supports two authentication methods:
### OIDC/OAuth (Preferred)
- Automatically configured if Cloudron provides OAuth environment variables
- Uses Cloudron's identity provider for single sign-on
- User roles mapped from Cloudron groups
- No additional configuration needed
### LDAP
- Automatically configured if Cloudron provides LDAP environment variables
- Uses Cloudron's LDAP server for authentication
- Groups are mapped to Rundeck roles
- Works with all Cloudron user accounts
## Troubleshooting
- If the app fails to start, check the Cloudron logs:
```
cloudron logs -f
```
- Common issues:
- Database connection problems: Check the PostgreSQL addon status
- Authentication issues: Verify LDAP/OIDC configuration
- File permissions: Ensure files in /app/data are owned by cloudron:cloudron
- Memory limits: If Rundeck is slow or crashing, consider increasing the memory limit
## Updating the Package
1. Update the app version in CloudronManifest.json
2. Update the Rundeck version in the Dockerfile
3. Make any necessary changes to configuration files
4. Rebuild and reinstall the package
## Backup and Restore
Cloudron automatically backs up the /app/data directory and PostgreSQL database. No additional configuration is required for backup functionality.
## Security Notes
- Rundeck stores sensitive data (credentials, private keys) in its database and file system
- All sensitive data is stored in the /app/data directory, which is backed up by Cloudron
- API keys and other secrets are encrypted using Jasypt encryption
- Always use HTTPS (provided by Cloudron) for secure access

View File

@@ -0,0 +1,57 @@
# framework.properties
#
# The base directory for the rundeck server
#
rdeck.base=/app/data
# Indicates a file contains credentials for writing to the output log file.
#
# The contents of this file must contain a single line with 2 comma separated
# strings:
# <username>,<password>
framework.output.password.file=/app/data/etc/output.password
# Framework crypto options
# framework.crypto.keystore.filename=
# framework.crypto.keystore.password=
# framework.crypto.secretkey.password=
# SSH connection timeout after a specified number of milliseconds.
# Default timeout is 30 seconds.
framework.ssh.timeout=30000
# Set the follow to true if you want ssh-agent forwarding to work.
framework.ssh.user.enableagentforward=false
# ssh key storage
framework.ssh.keypath=/app/data/.ssh
framework.ssh.keystore.path=/app/data/var/storage
# SSH authentication type (password or privateKey)
framework.ssh.authentication=privateKey
# Set this to true to use the ssh-key storage for ssh plugin tests
framework.ssh.fileCopier.use.storage=false
#
# Extra environment variables to pass to throttled/queued commands
#
# comma separated list of environment variables to pass from parent process to
# to child process as is
framework.env.retain=JVM_OPTS
# API Tokens File
framework.tokens.file=/app/data/etc/tokens.properties
# For Server URL and Port
framework.server.name=Rundeck
framework.server.hostname=${CLOUDRON_APP_DOMAIN}
framework.server.port=443
framework.server.url=https://${CLOUDRON_APP_DOMAIN}
# Define auth resources
framework.authorization.resource.file.path=/app/data/etc/resources.xml
# Logging
framework.log.dispatch.console.format=[%d{ISO8601}] %-5p %c{2} - %m%n
framework.log.dispatch.file=/app/data/var/logs/rundeck.log

View File

@@ -0,0 +1,22 @@
ldap {
com.dtolabs.rundeck.jetty.jaas.JettyCachingLdapLoginModule required
debug="true"
contextFactory="com.sun.jndi.ldap.LdapCtxFactory"
providerUrl="{{ldap.url}}"
bindDn="{{ldap.bindDn}}"
bindPassword="{{ldap.bindPassword}}"
authenticationMethod="simple"
forceBindingLogin="true"
userBaseDn="{{ldap.userBaseDn}}"
userRdnAttribute="uid"
userIdAttribute="uid"
userPasswordAttribute="userPassword"
userObjectClass="inetOrgPerson"
roleBaseDn="{{ldap.groupBaseDn}}"
roleNameAttribute="cn"
roleMemberAttribute="member"
roleObjectClass="groupOfNames"
cacheDurationMillis="300000"
supplementalRoles="user"
reportStatistics="true";
};

View File

@@ -0,0 +1,12 @@
oauth {
org.rundeck.jaas.jetty.JettyRolePropertyFileLoginModule required
debug="true"
useFirstPass="true"
supplementalRoles="user"
file="/app/data/etc/realm.properties";
com.dtolabs.rundeck.jetty.jaas.JettyOIDCUserGroupsLoginModule required
debug="true"
useFirstPass="false"
storePass="true";
};

View File

@@ -0,0 +1,34 @@
server {
listen 8080;
server_name localhost;
access_log /dev/stdout;
error_log /dev/stderr;
client_max_body_size 50M;
location / {
proxy_pass http://127.0.0.1:4440;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
# OIDC callback
location /user/oidclogin {
proxy_pass http://127.0.0.1:4440/user/oidclogin;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
}
}

View File

@@ -0,0 +1,2 @@
# Initial Admin User - will be set up by start.sh
admin:admin,user,admin

View File

@@ -0,0 +1,33 @@
# rundeck-config.properties
#
# Database connection
dataSource.driverClassName = org.postgresql.Driver
dataSource.url = ${RUNDECK_SERVER_DATASTORE_URL}
dataSource.username = ${CLOUDRON_POSTGRESQL_USERNAME}
dataSource.password = ${CLOUDRON_POSTGRESQL_PASSWORD}
dataSource.dbCreate = update
# Plugin installation
rundeck.plugin.dir = /app/data/libext
# Server settings
grails.serverURL = https://${CLOUDRON_APP_DOMAIN}
rundeck.gui.startpage = jobs
rundeck.enableSelfSignedCertDownload = false
rundeck.jetty.connector.forwarded = true
rundeck.security.useHMacRequestTokens = true
rundeck.security.csrf.referer.filterMethod = NONE
rundeck.api.tokens.duration.max = 30d
# Logging
rundeck.log4j.config.file = /app/data/server/config/log4j2.properties
rundeck.logging.dir = /app/data/var/logs
# File storage
rundeck.projectsStorageType=filesystem
rundeck.storage.provider.1.type=file
rundeck.storage.provider.1.path=/app/data/var/storage
rundeck.storage.converter.1.type=jasypt-encryption
rundeck.storage.converter.1.key=keys
rundeck.storage.converter.1.path=keys

View File

@@ -0,0 +1,104 @@
#!/bin/bash
set -eu
# Setup runtime environment
echo "Setting up Rundeck runtime environment..."
# Initialize data directories if they don't exist
for dir in etc server/data var/logs projects libext .ssh; do
if [ ! -d "/app/data/$dir" ]; then
mkdir -p "/app/data/$dir"
if [ -d "/tmp/data/$dir" ] && [ -n "$(ls -A "/tmp/data/$dir" 2>/dev/null)" ]; then
cp -r "/tmp/data/$dir/"* "/app/data/$dir/"
fi
fi
done
# Setup database connection
DB_URL="jdbc:postgresql://${CLOUDRON_POSTGRESQL_HOST}:${CLOUDRON_POSTGRESQL_PORT}/${CLOUDRON_POSTGRESQL_DATABASE}?user=${CLOUDRON_POSTGRESQL_USERNAME}&password=${CLOUDRON_POSTGRESQL_PASSWORD}"
export RUNDECK_SERVER_DATASTORE_URL="$DB_URL"
export RUNDECK_DATABASE_URL="$DB_URL"
export RUNDECK_DATABASE_DRIVER="org.postgresql.Driver"
export RUNDECK_DATABASE_USERNAME="${CLOUDRON_POSTGRESQL_USERNAME}"
export RUNDECK_DATABASE_PASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}"
# Generate initial admin password if not exists
if ! grep -q "^admin:" /app/data/etc/realm.properties 2>/dev/null; then
PASSWORD=$(openssl rand -hex 8)
echo "admin:admin,user,admin" > /app/data/etc/realm.properties
sed -i "s|{{ .password }}|$PASSWORD|g" /run/cloudron/app.json
else
sed -i "s|{{ .password }}|<existing password>|g" /run/cloudron/app.json
fi
# Update configurations
if [ -f "/app/data/etc/framework.properties" ]; then
# Set domain in framework.properties
sed -i "s|framework.server.url = .*|framework.server.url = https://${CLOUDRON_APP_DOMAIN}|g" /app/data/etc/framework.properties
sed -i "s|framework.server.hostname = .*|framework.server.hostname = ${CLOUDRON_APP_DOMAIN}|g" /app/data/etc/framework.properties
fi
if [ -f "/app/data/etc/rundeck-config.properties" ]; then
# Update database connection in rundeck-config.properties
sed -i "s|dataSource.url = .*|dataSource.url = ${RUNDECK_SERVER_DATASTORE_URL}|g" /app/data/etc/rundeck-config.properties
sed -i "s|grails.serverURL = .*|grails.serverURL = https://${CLOUDRON_APP_DOMAIN}|g" /app/data/etc/rundeck-config.properties
fi
# Configure authentication
if [[ -n "${CLOUDRON_OAUTH_IDENTIFIER:-}" ]]; then
echo "Configuring OAuth/OIDC authentication..."
export RUNDECK_SECURITY_OAUTH_ENABLED=true
export RUNDECK_SECURITY_OAUTH_CLIENTID="${CLOUDRON_OAUTH_CLIENT_ID}"
export RUNDECK_SECURITY_OAUTH_CLIENTSECRET="${CLOUDRON_OAUTH_CLIENT_SECRET}"
export RUNDECK_SECURITY_OAUTH_AUTHORIZEURL="${CLOUDRON_OAUTH_ORIGIN}/auth/realms/${CLOUDRON_OAUTH_IDENTIFIER}/protocol/openid-connect/auth"
export RUNDECK_SECURITY_OAUTH_TOKENURL="${CLOUDRON_OAUTH_ORIGIN}/auth/realms/${CLOUDRON_OAUTH_IDENTIFIER}/protocol/openid-connect/token"
export RUNDECK_SECURITY_OAUTH_USERINFOURI="${CLOUDRON_OAUTH_ORIGIN}/auth/realms/${CLOUDRON_OAUTH_IDENTIFIER}/protocol/openid-connect/userinfo"
cp /tmp/data/etc/jaas-oidc.conf /app/data/etc/jaas-oidc.conf
export RUNDECK_JAASLOGIN=true
export RDECK_JVM_OPTS="${RDECK_JVM_OPTS:-} -Drundeck.jaaslogin=true -Dloginmodule.name=oauth -Djava.security.auth.login.config=/app/data/etc/jaas-oidc.conf"
# Add necessary properties to rundeck-config.properties
echo "rundeck.security.oauth.enabled=true" >> /app/data/etc/rundeck-config.properties
echo "rundeck.security.oauth.clientId=${CLOUDRON_OAUTH_CLIENT_ID}" >> /app/data/etc/rundeck-config.properties
echo "rundeck.security.oauth.clientSecret=${CLOUDRON_OAUTH_CLIENT_SECRET}" >> /app/data/etc/rundeck-config.properties
echo "rundeck.security.oauth.authorizeUrl=${CLOUDRON_OAUTH_ORIGIN}/auth/realms/${CLOUDRON_OAUTH_IDENTIFIER}/protocol/openid-connect/auth" >> /app/data/etc/rundeck-config.properties
echo "rundeck.security.oauth.tokenUrl=${CLOUDRON_OAUTH_ORIGIN}/auth/realms/${CLOUDRON_OAUTH_IDENTIFIER}/protocol/openid-connect/token" >> /app/data/etc/rundeck-config.properties
echo "rundeck.security.oauth.userInfoUri=${CLOUDRON_OAUTH_ORIGIN}/auth/realms/${CLOUDRON_OAUTH_IDENTIFIER}/protocol/openid-connect/userinfo" >> /app/data/etc/rundeck-config.properties
echo "rundeck.security.oauth.autoCreateUsers=true" >> /app/data/etc/rundeck-config.properties
echo "rundeck.security.oauth.defaultRoles=user" >> /app/data/etc/rundeck-config.properties
elif [[ -n "${CLOUDRON_LDAP_SERVER:-}" ]]; then
echo "Configuring LDAP authentication..."
cp /tmp/data/etc/jaas-ldap.conf /app/data/etc/jaas-ldap.conf
# Replace placeholders in JAAS config
sed -i "s|{{ldap.url}}|${CLOUDRON_LDAP_SERVER}:${CLOUDRON_LDAP_PORT}|g" /app/data/etc/jaas-ldap.conf
sed -i "s|{{ldap.bindDn}}|${CLOUDRON_LDAP_BIND_DN}|g" /app/data/etc/jaas-ldap.conf
sed -i "s|{{ldap.bindPassword}}|${CLOUDRON_LDAP_BIND_PASSWORD}|g" /app/data/etc/jaas-ldap.conf
sed -i "s|{{ldap.userBaseDn}}|${CLOUDRON_LDAP_USERS_BASE_DN}|g" /app/data/etc/jaas-ldap.conf
sed -i "s|{{ldap.groupBaseDn}}|${CLOUDRON_LDAP_GROUPS_BASE_DN}|g" /app/data/etc/jaas-ldap.conf
export RUNDECK_JAASLOGIN=true
export RDECK_JVM_OPTS="${RDECK_JVM_OPTS:-} -Drundeck.jaaslogin=true -Dloginmodule.name=ldap -Djava.security.auth.login.config=/app/data/etc/jaas-ldap.conf"
# Enable JAAS LDAP in rundeck-config.properties
echo "rundeck.security.jaasLoginModuleName=ldap" >> /app/data/etc/rundeck-config.properties
echo "rundeck.security.jaasProviderName=ldap" >> /app/data/etc/rundeck-config.properties
echo "rundeck.jaaslogin=true" >> /app/data/etc/rundeck-config.properties
echo "rundeck.feature.caseInsensitiveUsername.enabled=true" >> /app/data/etc/rundeck-config.properties
echo "rundeck.security.syncLdapUser=true" >> /app/data/etc/rundeck-config.properties
else
# Use file-based authentication
echo "Using file-based authentication..."
export RDECK_JVM_OPTS="${RDECK_JVM_OPTS:-} -Drundeck.jaaslogin=true -Dloginmodule.name=file -Djava.security.auth.login.config=/app/data/etc/jaas-file.conf"
echo 'RDpropertyfilelogin { org.eclipse.jetty.jaas.spi.PropertyFileLoginModule required debug="true" file="/app/data/etc/realm.properties"; };' > /app/data/etc/jaas-file.conf
echo "rundeck.security.jaasLoginModuleName=file" >> /app/data/etc/rundeck-config.properties
echo "rundeck.security.jaasProviderName=file" >> /app/data/etc/rundeck-config.properties
fi
# Set permissions
chown -R cloudron:cloudron /app/data
echo "Starting Rundeck services..."
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf

View File

@@ -0,0 +1,29 @@
[supervisord]
nodaemon=true
user=root
logfile=/dev/stdout
logfile_maxbytes=0
pidfile=/var/run/supervisord.pid
[program:rundeck]
command=java -Xmx512m -Dserver.http.port=4440 -Drdeck.base=/app/data -jar /app/code/rundeck/webapps/rundeck.war
directory=/app/code/rundeck
user=cloudron
environment=RDECK_BASE="/app/data",RUNDECK_SERVER_DATASTORE_URL="%(ENV_RUNDECK_SERVER_DATASTORE_URL)s",RUNDECK_SERVER_DATASTORE_DRIVER="%(ENV_RUNDECK_SERVER_DATASTORE_DRIVER)s",RUNDECK_GRAILS_URL="%(ENV_RUNDECK_GRAILS_URL)s",RUNDECK_SERVER_CONTEXTPATH="%(ENV_RUNDECK_SERVER_CONTEXTPATH)s",RUNDECK_SERVER_FORWARDED=%(ENV_RUNDECK_SERVER_FORWARDED)s,RUNDECK_LOGGING_STRATEGY="%(ENV_RUNDECK_LOGGING_STRATEGY)s",SERVER_SERVLET_CONTEXT_PATH="%(ENV_SERVER_SERVLET_CONTEXT_PATH)s",RUNDECK_JAASLOGIN=%(ENV_RUNDECK_JAASLOGIN)s,RUNDECK_SERVER_ADDRESS=%(ENV_RUNDECK_SERVER_ADDRESS)s,RUNDECK_SERVER_PORT=%(ENV_RUNDECK_SERVER_PORT)s
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
priority=10
startretries=5
stopwaitsecs=60
[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
priority=20

View File

@@ -0,0 +1,170 @@
# Cloudron Packaging Workspace
This workspace contains development tools and upstream source repositories for Cloudron application packaging.
## 🏗️ Workspace Structure
```
CloudronPackagingWorkspace/
├── README.md # This file
├── Docker/ (gitignored) # Upstream application sources (~56 apps)
├── NonDocker/ (gitignored) # Non-Docker application sources
├── UpstreamVendor-Clone.sh # Clone all upstream repositories
└── UpstreamVendor-Update.sh # Update existing repositories
```
## 🚀 Setup Instructions
### Initial Setup
```bash
cd CloudronPackagingWorkspace/
# Create Docker directory for upstream sources
mkdir -p Docker
# Make scripts executable
chmod +x *.sh
# Clone all upstream vendor repositories
./UpstreamVendor-Clone.sh
```
This will perform a clone of all upstream vendor software/Docker repositories for every application that KNEL is packaging for Cloudron deployment.
### Keeping Sources Updated
```bash
# Update all existing checkouts to latest versions
./UpstreamVendor-Update.sh
```
## 📦 Available Applications
The workspace contains ~56 upstream application repositories including:
### High Priority Applications
- **apisix** - Apache APISIX API Gateway
- **jenkins** - Jenkins CI/CD Platform
- **grist-core** - Grist Database/Spreadsheet
- **rundeck** - Rundeck Job Scheduler
- **reviewboard** - ReviewBoard Code Review
- **consuldemocracy** - Consul Democracy Platform
### Development & Infrastructure Tools
- **InvenTree** - Inventory Management System
- **elabftw** - Laboratory Management
- **netbox-docker** - Network Documentation
- **signoz** - Observability Platform
- **healthchecks** - Health Monitoring
- **fleet** - Device Management
### Productivity & Specialized Applications
- **huginn** - Web Automation
- **windmill** - Workflow Automation
- **docassemble** - Document Assembly
- **jamovi** - Statistical Analysis
- And many more...
## 🛠️ Development Workflow
### Using the Workspace
1. **Source Access**: All upstream sources are available in `Docker/[appname]/`
2. **Development**: Use the `tsys-cloudron-packaging` container for all work
3. **Package Creation**: Create packages in separate temporary directories
4. **Git Exclusion**: All upstream sources are gitignored to keep repository clean
### Container Development
```bash
# Access development container
docker exec -it tsys-cloudron-packaging bash
# Navigate to workspace
cd /workspace
# Access application source
cd CloudronPackagingWorkspace/Docker/[appname]/
# Create new package (outside of workspace)
cd /workspace
mkdir -p [appname]_package_new
```
## 📋 Workspace Management
### Adding New Applications
1. Update `UpstreamVendor-Clone.sh` with new repository URL
2. Run the clone script to fetch the new application
3. Add application to priority list in `TASKS.md`
### Removing Applications
1. Remove directory from `Docker/`
2. Update clone script to prevent future re-cloning
3. Update task lists and documentation
### Repository Updates
- **Frequency**: Weekly or before starting new package development
- **Method**: Run `./UpstreamVendor-Update.sh`
- **Verification**: Check for breaking changes in upstream
## ⚠️ Important Notes
### Git Exclusions
- **Docker/**: All contents are gitignored
- **NonDocker/**: All contents are gitignored
- This keeps the main repository clean while preserving access to sources
### Repository Integrity
- Never commit upstream sources to the main repository
- Use temporary directories for package development
- Move final packages to `CloudronPackages/` when complete
### Source Licenses
- Each upstream repository maintains its own license
- Review license compatibility before packaging
- Include appropriate license information in final packages
## 🔧 Script Maintenance
### UpstreamVendor-Clone.sh
- Contains git clone commands for all upstream repositories
- Handles both GitHub and other git hosting platforms
- Includes error handling for failed clones
### UpstreamVendor-Update.sh
- Updates existing repositories to latest versions
- Skips missing directories gracefully
- Provides summary of update status
### Customization
Edit scripts as needed to:
- Add new repository sources
- Change clone depth or branch targets
- Modify update behavior
- Handle special cases
## 📊 Workspace Statistics
- **Total Applications**: 56 repositories
- **Repository Size**: ~2-3 GB total (varies by application)
- **Update Frequency**: Weekly recommended
- **Clone Time**: ~15-30 minutes for full clone
## 🤝 Team Usage
### For Developers
1. Use `./UpstreamVendor-Clone.sh` on first setup
2. Run `./UpstreamVendor-Update.sh` weekly or before new package work
3. Always work in the containerized environment
4. Never commit workspace contents to git
### For DevOps
1. Monitor disk space usage of workspace
2. Ensure container environment has access to workspace
3. Backup workspace if needed for disaster recovery
4. Update scripts when adding/removing applications
---
**Last Updated**: 2025-01-04
**Maintained By**: KNEL/TSYS Development Team
**Part of**: [KNEL Production Containers](../README.md) packaging project

View File

@@ -0,0 +1,214 @@
#!/bin/bash
export PS4='(${BASH_SOURCE}:${LINENO}): - [${SHLVL},${BASH_SUBSHELL},$?] $ '
function error_out()
{
echo "Bailing out. See above for reason...."
exit 1
}
function handle_failure() {
local lineno=$1
local fn=$2
local exitstatus=$3
local msg=$4
local lineno_fns=${0% 0}
if [[ "$lineno_fns" != "-1" ]] ; then
lineno="${lineno} ${lineno_fns}"
fi
echo "${BASH_SOURCE[0]}: Function: ${fn} Line Number : [${lineno}] Failed with status ${exitstatus}: $msg"
}
trap 'handle_failure "${BASH_LINENO[*]}" "$LINENO" "${FUNCNAME[*]:-script}" "$?" "$BASH_COMMAND"' ERR
set -o errexit
set -o nounset
set -o pipefail
set -o functrace
export GIT_REPO_LIST
GIT_REPO_LIST=(
####################
# Vp techops stuff
####################
#https://projects.knownelement.com/issues/179
https://github.com/apache/apisix.git
#https://projects.knownelement.com/issues/204
https://github.com/target/goalert.git
#https://projects.knownelement.com/issues/189
https://github.com/consuldemocracy/consuldemocracy.git
#https://projects.knownelement.com/issues/195
https://github.com/fleetdm/fleet.git
#https://projects.knownelement.com/issues/227
https://github.com/fonoster/fonoster.git
#https://projects.knownelement.com/issues/192
https://github.com/healthchecks/healthchecks.git
#https://projects.knownelement.com/issues/209
https://github.com/juspay/hyperswitch
#https://projects.knownelement.com/issues/201
https://github.com/netbox-community/netbox-docker.git
# https://projects.knownelement.com/issues/205
https://github.com/openboxes/openboxes-docker.git
#https://projects.knownelement.com/issues/316
https://github.com/openfiletax/openfile.git
#https://projects.knownelement.com/issues/211
https://github.com/GemGeorge/SniperPhish-Docker.git
#https://projects.knownelement.com/issues/309
https://github.com/datahub-project/datahub.git
#https://projects.knownelement.com/issues/54
https://github.com/wiredlush/easy-gate.git
#https://projects.knownelement.com/issues/208
https://github.com/Payroll-Engine/PayrollEngine.git
#https://projects.knownelement.com/issues/194
https://github.com/huginn/huginn.git
#https://projects.knownelement.com/issues/191
https://github.com/gristlabs/grist-core
#https://projects.knownelement.com/issues/277
https://github.com/jhpyle/docassemble.git
#https://projects.knownelement.com/issues/273
https://github.com/kazhuravlev/database-gateway.git
#https://projects.knownelement.com/issues/217
https://github.com/rundeck/rundeck.git
#https://projects.knownelement.com/issues/222
https://github.com/SchedMD/slurm.git
https://github.com/giovtorres/slurm-docker-cluster.git
#https://projects.knownelement.com/issues/225
https://github.com/rathole-org/rathole.git
#https://projects.knownelement.com/issues/234
https://github.com/jenkinsci/jenkins.git
#https://projects.knownelement.com/issues/322
https://github.com/runmedev/runme.git
#https://projects.knownelement.com/issues/301
https://github.com/apache/seatunnel
#https://projects.knownelement.com/issues/271
https://github.com/thecatlady/docker-webhook
####################
# CTO Stuff
####################
#https://projects.knownelement.com/issues/173
https://github.com/inventree/InvenTree.git
#https://projects.knownelement.com/issues/180
https://github.com/Cloud-RF/tak-server
#https://projects.knownelement.com/issues/178
https://github.com/midday-ai/midday.git
#https://projects.knownelement.com/issues/181
https://github.com/killbill/killbill.git
#https://projects.knownelement.com/issues/184
https://github.com/chirpstack/chirpstack.git
#https://projects.knownelement.com/issues/185
https://github.com/CraigChat/craig.git
#https://projects.knownelement.com/issues/188
https://github.com/elabftw/elabftw.git
#https://projects.knownelement.com/issues/196
https://github.com/jamovi/jamovi.git
#https://projects.knownelement.com/issues/197
https://github.com/INTI-CMNB/KiBot.git
#https://projects.knownelement.com/issues/214
https://github.com/Resgrid/Core
#https://projects.knownelement.com/issues/216
https://github.com/reviewboard/reviewboard.git
#https://projects.knownelement.com/issues/218
https://gitlab.com/librespacefoundation/satnogs/docker-kaitai.git
https://gitlab.com/librespacefoundation/satnogs/docker-satnogs-webgui.git
#https://projects.knownelement.com/issues/219
https://github.com/f4exb/sdrangel-docker
#https://projects.knownelement.com/issues/221
https://github.com/SigNoz/signoz.git
#https://projects.knownelement.com/issues/228
https://github.com/sebo-b/warp.git
#https://projects.knownelement.com/issues/272
https://github.com/jgraph/docker-drawio
#https://projects.knownelement.com/issues/274
https://github.com/openblocks-dev/openblocks.git
#https://projects.knownelement.com/issues/276
https://github.com/wireviz/wireviz-web.git
#https://projects.knownelement.com/issues/278
https://github.com/opulo-inc/autobom.git
#https://projects.knownelement.com/issues/279
https://github.com/PLMore/PLMore
#https://projects.knownelement.com/issues/282
https://github.com/manyfold3d/manyfold.git
#https://projects.knownelement.com/issues/283
https://github.com/langfuse/oss-llmops-stack.git
#https://projects.knownelement.com/issues/286
https://github.com/HeyPuter/puter.git
#https://projects.knownelement.com/issues/285
https://github.com/windmill-labs/windmill.git
#https://projects.knownelement.com/issues/326
https://github.com/sbabic/swupdate.git
#https://projects.knownelement.com/issues/300
https://github.com/mendersoftware/mender-server.git
#https://projects.knownelement.com/issues/50
https://github.com/vanila-io/wireflow.git
#https://projects.knownelement.com/issues/226
https://github.com/nautechsystems/nautilus_trader.git
#TBD
https://github.com/funmusicplace/mirlo.git
)
cd Docker
IFS=$'\n\t'
for GIT_REPO in ${GIT_REPO_LIST[@]};do
git clone --depth 1 $GIT_REPO || true
done

View File

@@ -0,0 +1,44 @@
#!/bin/bash
export PS4='(${BASH_SOURCE}:${LINENO}): - [${SHLVL},${BASH_SUBSHELL},$?] $ '
function error_out()
{
echo "Bailing out. See above for reason...."
exit 1
}
function handle_failure() {
local lineno=$1
local fn=$2
local exitstatus=$3
local msg=$4
local lineno_fns=${0% 0}
if [[ "$lineno_fns" != "-1" ]] ; then
lineno="${lineno} ${lineno_fns}"
fi
echo "${BASH_SOURCE[0]}: Function: ${fn} Line Number : [${lineno}] Failed with status ${exitstatus}: $msg"
}
trap 'handle_failure "${BASH_LINENO[*]}" "$LINENO" "${FUNCNAME[*]:-script}" "$?" "$BASH_COMMAND"' ERR
set -o errexit
set -o nounset
set -o pipefail
set -o functrace
cd Docker
GIT_REPO_LIST="$(ls -d */)"
IFS=$'\n\t'
for GIT_REPO in ${GIT_REPO_LIST[@]};
do
CURRENT_DIR=$(realpath $PWD)
echo "Updating from $GIT_REPO..."
cd $GIT_REPO
git pull
cd $CURRENT_DIR
done

1
GEMINI.md Symbolic link
View File

@@ -0,0 +1 @@
AGENT.md

524
GIT_WORKFLOW.md Normal file
View File

@@ -0,0 +1,524 @@
# Git Workflow for Cloudron Packaging
## 🌿 Branch Strategy
### Branch Hierarchy & Workflow Pattern
```
main (production-ready packages)
↑ PR (requires YOUR approval)
integration (staging for multiple packages)
↑ merge feature branch directly (no PR needed)
feature/package-[appname] (individual development)
↑ create from integration
```
**One Package = One Branch Pattern**:
1. Create `feature/package-[appname]` from `integration`
2. Develop complete package in feature branch
3. Merge feature branch to `integration` (direct merge)
4. When multiple packages ready, create PR `integration``main` (requires your approval)
### Branch Purposes
#### `main` - Production Branch
- **Purpose**: Stable, tested, production-ready packages
- **Protection**: ALL commits must come via Pull Request from `integration`
- **Approval Required**: Project maintainer approval mandatory
- **Quality Gate**: Full validation and approval before merge
- **Branch Protection**: Direct pushes blocked, PR reviews required
#### `integration` - Staging Branch
- **Purpose**: Collection point for completed packages before production
- **Source**: Direct merges from individual `feature/package-*` branches (no PR needed)
- **Protection**: Open for direct pushes from feature branches
- **Testing**: Integration testing and cross-package validation
- **Duration**: Accumulates packages until batch ready for production release
#### `feature/package-[appname]` - Development Branches
- **Purpose**: Individual application packaging development
- **Naming**: `feature/package-jenkins`, `feature/package-apisix`, etc.
- **Lifespan**: Created from `main`, merged to `integration`, then deleted
- **Scope**: Single application focus, complete package development
#### `hotfix/[appname]-[issue]` - Emergency Fixes
- **Purpose**: Critical fixes to existing packages
- **Source**: Created from `main`
- **Target**: Merge directly to `main` after testing
- **Examples**: `hotfix/jenkins-security-update`
---
## 🔄 Development Workflow
### 1. Starting New Package Development
```bash
# Start from integration branch (not main)
git checkout integration
git pull origin integration
# Create feature branch
git checkout -b feature/package-[appname]
# Push branch to remote
git push -u origin feature/package-[appname]
```
### 2. Development Process
```bash
# Work in containerized environment
docker exec -it tsys-cloudron-packaging bash
cd /workspace
# Create package
mkdir -p [appname]_package_new
cd [appname]_package_new
# ... develop package files ...
# Test package
docker build -t test/[appname]:dev .
docker run --rm test/[appname]:dev
# Move to final location when ready
mv /workspace/[appname]_package_new ./CloudronPackages/[AppName]/
```
### 3. Committing Changes
```bash
# Add package files
git add CloudronPackages/[AppName]/
# Update task tracking
git add TASKS.md WORKLOG.md
# Commit with proper message
git commit -m "feat([appname]): add Cloudron package
- Implements [AppName] packaging for Cloudron platform
- Includes proper addon integration and health checks
- Tested with build and basic functionality
- Estimated complexity: [Low/Medium/High]
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>"
# Push to remote
git push origin feature/package-[appname]
```
### 4. Merge to Integration Branch
```bash
# Push final changes to feature branch
git push origin feature/package-[appname]
# Switch to integration and merge feature branch directly
git checkout integration
git pull origin integration
# Merge feature branch (no PR needed for integration)
git merge feature/package-[appname]
# Push to integration
git push origin integration
# Clean up feature branch
git branch -d feature/package-[appname]
git push origin --delete feature/package-[appname]
```
### 5. Production Release via Pull Request
```bash
# When ready for production (multiple packages in integration)
git checkout integration
git pull origin integration
# Create PR from integration to main using tea CLI
tea pr create \
--title "release: $(date +%Y-%m-%d) package release" \
--body "$(cat <<'EOF'
## Release Summary
Production release containing validated packages ready for deployment.
## Packages Included
- [AppName1]: [brief description]
- [AppName2]: [brief description]
- [AppName3]: [brief description]
## Validation Completed
- [x] All packages build successfully
- [x] Integration testing completed
- [x] No conflicts between packages
- [x] Documentation updated
- [x] Quality standards met
## Impact
- Ready for production deployment
- No breaking changes
- All packages follow established patterns
**Requires maintainer approval before merge**
EOF
)" \
--base main \
--head integration
# Wait for maintainer approval and merge
# After merge, tag the release
git checkout main
git pull origin main
git tag -a v$(date +%Y.%m.%d) -m "Release $(date +%Y-%m-%d): [package list]"
git push origin main --tags
```
---
## 🍵 Gitea & Tea CLI Integration
### Tea CLI Setup
```bash
# Install tea CLI (if not already installed)
# Visit: https://gitea.com/gitea/tea#installation
# Configure tea for your Gitea instance
tea login add --name knel --url https://git.knownelement.com --token [your-token]
# Verify configuration
tea whoami
```
### PR Templates with Tea
#### Feature Package PR Template
```bash
# Template for individual package PRs to integration
tea pr create \
--title "feat(${app_name}): add Cloudron package" \
--body "$(cat <<EOF
## 📦 Package: ${app_name}
### Summary
Implements ${app_name} Cloudron package with proper addon integration and follows established patterns.
### 🔧 Technical Details
- **Base Image**: cloudron/base:4.2.0
- **Addons Required**: ${addons_list}
- **Memory Limit**: ${memory_limit}MB
- **Health Check**: ${health_check_path}
- **Complexity**: ${complexity}
### 📋 Changes
- ✅ CloudronManifest.json with proper addon configuration
- ✅ Dockerfile following Cloudron conventions
- ✅ start.sh with initialization and error handling
- ✅ Configuration files and templates
- ✅ Build notes documentation
### 🧪 Testing Checklist
- [x] Docker build successful
- [x] Basic functionality verified
- [x] Health check endpoint working
- [x] Addon integration tested
- [ ] Full Cloudron deployment test (if available)
### 📚 Documentation
- [x] Build notes complete
- [x] Configuration documented
- [x] Known limitations noted
- [x] TASKS.md updated
**Auto-merge after CI passes ✅**
EOF
)" \
--base integration \
--head feature/package-${app_name}
```
#### Production Release PR Template
```bash
# Template for integration → main PRs (requires approval)
tea pr create \
--title "release: $(date +%Y-%m-%d) production package release" \
--body "$(cat <<EOF
## 🚀 Production Release: $(date +%B %d, %Y)
### 📦 Packages Ready for Production
$(git log --oneline integration ^main --grep="feat(" | sed 's/.*feat(\([^)]*\)).*/- **\1**: Ready for deployment/')
### ✅ Validation Summary
- [x] All packages build successfully without errors
- [x] Integration testing completed across packages
- [x] No resource conflicts or port collisions
- [x] Documentation complete and up-to-date
- [x] Quality standards met for all packages
- [x] Security review completed
### 🔍 Quality Gates Passed
- **Build Success Rate**: 100%
- **Test Coverage**: All packages validated
- **Documentation**: Complete
- **Standards Compliance**: ✅
### 📊 Impact Assessment
- **New Packages**: $(git log --oneline integration ^main --grep="feat(" | wc -l)
- **Breaking Changes**: None
- **Deployment Risk**: Low
- **Rollback Plan**: Available
### 🎯 Post-Merge Actions
- [ ] Tag release: v$(date +%Y.%m.%d)
- [ ] Update deployment documentation
- [ ] Notify deployment team
- [ ] Monitor initial deployments
**⚠️ REQUIRES MAINTAINER APPROVAL ⚠️**
EOF
)" \
--base main \
--head integration
```
### Tea CLI Common Commands
```bash
# List open PRs
tea pr list
# Check PR status
tea pr view [pr-number]
# Close/merge PR (for maintainers)
tea pr merge [pr-number]
# Create draft PR
tea pr create --draft
# Add reviewers to PR
tea pr create --reviewer @maintainer
# Link PR to issue
tea pr create --body "Closes #123"
```
### Automated Workflow Helpers
```bash
# Quick PR creation function (add to ~/.bashrc)
create_package_pr() {
local app_name=$1
local complexity=${2:-"Medium"}
local addons=${3:-"localstorage, postgresql"}
tea pr create \
--title "feat(${app_name}): add Cloudron package" \
--body "Implements ${app_name} package. Complexity: ${complexity}. Addons: ${addons}" \
--base integration \
--head feature/package-${app_name}
}
# Usage: create_package_pr "jenkins" "High" "localstorage, postgresql, redis"
```
---
## 📋 Commit Message Standards
### Commit Types
- **feat(app)**: New package implementation
- **fix(app)**: Bug fix in existing package
- **docs**: Documentation updates
- **chore**: Maintenance tasks
- **test**: Testing improvements
- **refactor(app)**: Package improvements without functional changes
### Message Format
```
type(scope): brief description
Detailed description of changes:
- Key changes made
- Testing performed
- Any breaking changes or considerations
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
```
### Examples
```bash
feat(jenkins): add Jenkins CI/CD Cloudron package
- Implements complete Jenkins packaging with persistent storage
- Includes supervisor configuration for multi-process management
- Integrates with PostgreSQL addon for build history
- Tested with basic job creation and execution
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
```
```bash
fix(apisix): resolve etcd connection timeout issue
- Increases etcd connection timeout from 5s to 30s
- Adds proper wait-for-etcd startup logic
- Improves error logging for debugging
- Tested with cold start scenarios
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
```
---
## 🛡️ Branch Protection Rules
### Master Branch Protection
- **Require pull request reviews**: 1 approver minimum
- **Dismiss stale reviews**: When new commits pushed
- **Require status checks**: All CI/CD passes
- **Require branches up to date**: Before merging
- **Include administrators**: Apply rules to admins
### Integration Branch Protection
- **Require pull request reviews**: 1 approver (can be self-approved)
- **Allow force pushes**: For integration management
- **Delete head branches**: Automatic cleanup
---
## 🔄 Release Management
### Weekly Release Cycle
- **Monday**: Integration branch validation begins
- **Wednesday**: Final validation and testing
- **Friday**: Merge to main and tag release
### Release Versioning
- **Format**: `v2025.01.15` (date-based)
- **Tags**: Annotated tags with package list
- **Notes**: Generated from commit messages
### Release Content
Each release includes:
- List of new packages added
- List of packages updated
- Known issues or limitations
- Upgrade instructions if needed
---
## 🧪 Testing Strategy
### Individual Package Testing
```bash
# In feature branch - basic functionality
docker build -t test/[appname]:feature .
docker run --rm -p 8080:8080 test/[appname]:feature
# Local Cloudron testing (if available)
cloudron install --image test/[appname]:feature
```
### Integration Testing
```bash
# In integration branch - cross-package testing
# Test multiple packages don't conflict
# Verify resource usage within limits
# Check for port conflicts or naming issues
```
### Production Validation
```bash
# Before main merge - production readiness
# Full Cloudron deployment testing
# Performance and stability validation
# Documentation completeness check
```
---
## 📊 Workflow Metrics
### Development Velocity
- **Target**: 2-3 packages per week
- **Measurement**: Feature branch creation to integration merge
- **Quality Gate**: Zero critical issues in integration
### Integration Success Rate
- **Target**: >95% of packages pass integration testing
- **Measurement**: Packages requiring hotfixes after integration
- **Quality Gate**: All tests pass before main merge
### Release Stability
- **Target**: <5% of releases require hotfixes
- **Measurement**: Hotfix commits per release
- **Quality Gate**: Production stability maintained
---
## 🚨 Emergency Procedures
### Critical Package Issue
1. Create `hotfix/[appname]-[issue]` from `main`
2. Implement minimal fix
3. Test fix thoroughly
4. Merge directly to `main` with approval
5. Cherry-pick to `integration` if needed
6. Update affected downstream deployments
### Integration Branch Issues
1. Identify problematic package
2. Revert specific merge if possible
3. Return package to feature branch for fixes
4. Re-test integration after fix
### Repository Corruption
1. Backup current state
2. Identify last known good state
3. Reset affected branches
4. Reapply recent changes manually if needed
5. Communicate impact to team
---
## 🔧 Git Configuration
### Recommended Git Config
```bash
# Helpful aliases
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual '!gitk'
# Better logging
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
# Push settings
git config --global push.default simple
git config --global pull.rebase true
```
### Team Settings
```bash
# Consistent line endings
git config --global core.autocrlf input
# Editor setup
git config --global core.editor "code --wait"
# Name and email (team members)
git config --global user.name "Your Name"
git config --global user.email "your.email@knel.com"
```
---
**Last Updated**: 2025-01-04
**Next Review**: 2025-02-01
**Maintained By**: KNEL/TSYS Development Team

8
KNEL-Cloudron/README.md Normal file
View File

@@ -0,0 +1,8 @@
# README for KNELProductionContainers/Cloudron
This directory contains the KNEL specific configurations for Cloudron deployed applications that we have packaged up and deployed in-house.
If you want to see the code for what we put into the app store, that's in:
- ../CloudronPackagingWorkspace
- ../CloudronPackages

View File

@@ -0,0 +1 @@
# dockerfile for an app at tsys

View File

@@ -0,0 +1 @@
# dev environment for an app at tsys

View File

@@ -0,0 +1,5 @@
# app docker compose file for tsys
## app name
## ports
## deps

View File

@@ -0,0 +1 @@
# dockerfile for an app at tsys

View File

@@ -0,0 +1 @@
# dev environment for an app at tsys

View File

@@ -0,0 +1,5 @@
# app docker compose file for tsys
## app name
## ports
## deps

View File

@@ -0,0 +1 @@
# dockerfile for an app at tsys

Some files were not shown because too many files have changed in this diff Show More