This commit is contained in:
2025-04-21 19:21:06 -05:00
parent a4db3a38d8
commit 113d1cd0fd
307 changed files with 5 additions and 5 deletions

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

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,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 @@
This directory contains template files for the application at FQDN indidicated by the parent directory. They will be processed using mo (bash mustache).

View File

@@ -0,0 +1 @@
This directory contains final docker compose files for the application at FQDN indidicated by the parent directory.

View File

@@ -0,0 +1 @@
This directory contains files from the vendor unmodified. They serve as a base for the input-files sibling directory

View File

@@ -0,0 +1 @@
We need an SSH portal. Use xterm.js to find solutions.