Initial Keila Cloudron package
This commit is contained in:
9
CHANGELOG
Normal file
9
CHANGELOG
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[0.1.0]
|
||||||
|
* Initial Cloudron package for Keila v0.14.7
|
||||||
|
* PostgreSQL database integration
|
||||||
|
* SMTP configuration via Cloudron mail addon
|
||||||
|
* Persistent data storage in /app/data
|
||||||
|
* Nginx reverse proxy configuration
|
||||||
|
* Automatic secret key generation
|
||||||
|
* Default admin user creation
|
||||||
|
* Security hardening with disabled registration
|
37
CloudronManifest.json
Normal file
37
CloudronManifest.json
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"id": "io.keila.cloudronapp",
|
||||||
|
"title": "Keila",
|
||||||
|
"author": "Pentacent",
|
||||||
|
"description": "Open-source newsletter tool for creating and sending email campaigns. An alternative to Mailchimp and Sendinblue.",
|
||||||
|
"tagline": "Self-hosted newsletter and email marketing platform",
|
||||||
|
"version": "0.14.7",
|
||||||
|
"healthCheckPath": "/",
|
||||||
|
"httpPort": 4000,
|
||||||
|
"manifestVersion": 2,
|
||||||
|
"website": "https://www.keila.io",
|
||||||
|
"contactEmail": "hello@keila.io",
|
||||||
|
"icon": "file://icon.png",
|
||||||
|
"tags": [
|
||||||
|
"email",
|
||||||
|
"newsletter",
|
||||||
|
"marketing",
|
||||||
|
"campaigns"
|
||||||
|
],
|
||||||
|
"memoryLimit": 536870912,
|
||||||
|
"addons": {
|
||||||
|
"postgresql": {},
|
||||||
|
"sendmail": {},
|
||||||
|
"localstorage": {}
|
||||||
|
},
|
||||||
|
"minBoxVersion": "7.0.0",
|
||||||
|
"postInstallMessage": "file://POSTINSTALL.md",
|
||||||
|
"changelog": "file://CHANGELOG",
|
||||||
|
"optionalSso": false,
|
||||||
|
"tcpPorts": {
|
||||||
|
"KEILA_PORT": {
|
||||||
|
"title": "Keila HTTP Port",
|
||||||
|
"description": "Keila HTTP Port",
|
||||||
|
"containerPort": 4000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
Dockerfile
Normal file
43
Dockerfile
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
FROM cloudron/base:4.2.0
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN mkdir -p /app/code /app/data
|
||||||
|
WORKDIR /app/code
|
||||||
|
|
||||||
|
# Install Elixir and dependencies
|
||||||
|
RUN curl -fSL https://github.com/elixir-lang/elixir/releases/download/v1.15.7/elixir-otp-26.zip -o elixir.zip \
|
||||||
|
&& unzip elixir.zip -d /opt/elixir \
|
||||||
|
&& rm elixir.zip \
|
||||||
|
&& ln -s /opt/elixir/bin/* /usr/local/bin/ \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y git build-essential cmake nodejs npm postgresql-client \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV MIX_ENV=prod
|
||||||
|
ENV PATH="/opt/elixir/bin:$PATH"
|
||||||
|
|
||||||
|
# Clone and build Keila
|
||||||
|
RUN git clone --depth 1 --branch v0.14.7 https://github.com/pentacent/keila.git . \
|
||||||
|
&& mix local.hex --force \
|
||||||
|
&& mix local.rebar --force \
|
||||||
|
&& mix deps.get --only prod \
|
||||||
|
&& mix deps.compile \
|
||||||
|
&& cd assets && npm ci && npm run deploy && cd .. \
|
||||||
|
&& mix phx.digest \
|
||||||
|
&& mix release
|
||||||
|
|
||||||
|
# Copy initialization data
|
||||||
|
RUN cp -r _build/prod/rel/keila /tmp/keila-release
|
||||||
|
|
||||||
|
# Copy start script
|
||||||
|
COPY start.sh /app/code/start.sh
|
||||||
|
COPY nginx.conf /etc/nginx/sites-available/default
|
||||||
|
|
||||||
|
# Set permissions
|
||||||
|
RUN chmod +x /app/code/start.sh \
|
||||||
|
&& chown -R cloudron:cloudron /app/code /app/data /tmp/keila-release
|
||||||
|
|
||||||
|
EXPOSE 4000
|
||||||
|
|
||||||
|
CMD ["/app/code/start.sh"]
|
28
POSTINSTALL.md
Normal file
28
POSTINSTALL.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Keila Installation Complete
|
||||||
|
|
||||||
|
Keila has been successfully installed on your Cloudron!
|
||||||
|
|
||||||
|
## Default Administrator Account
|
||||||
|
|
||||||
|
- **Email**: admin@your-domain.com
|
||||||
|
- **Password**: Check `/app/data/root_credentials` file or the application logs for the generated password
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
1. Log in using the administrator credentials above
|
||||||
|
2. Create your first newsletter campaign
|
||||||
|
3. Set up your email sending configuration (if not using Cloudron's built-in SMTP)
|
||||||
|
4. Create sign-up forms for your newsletters
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
- User registration is disabled by default for security
|
||||||
|
- All data is stored in `/app/data` and will persist across updates
|
||||||
|
- Email sending is configured to use Cloudron's SMTP service
|
||||||
|
- File uploads are stored in `/app/data/uploads`
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
- Documentation: https://www.keila.io/docs
|
||||||
|
- GitHub: https://github.com/pentacent/keila
|
||||||
|
- Issues: Please report Cloudron-specific issues to the package maintainer
|
143
README.md
Normal file
143
README.md
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
# Keila Cloudron Package
|
||||||
|
|
||||||
|
This is a Cloudron package for [Keila](https://www.keila.io), an open-source newsletter tool and alternative to Mailchimp and Sendinblue.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Newsletter Campaigns**: Create and send email campaigns
|
||||||
|
- **Sign-up Forms**: Generate customizable subscription forms
|
||||||
|
- **Multiple Email Providers**: Support for AWS SES, Sendgrid, Mailgun, Postmark, and SMTP
|
||||||
|
- **Self-hosted**: Complete control over your data and newsletters
|
||||||
|
- **PostgreSQL Integration**: Reliable database storage via Cloudron addon
|
||||||
|
- **SMTP Configuration**: Automatic email sending via Cloudron's mail service
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Cloudron instance with CLI installed
|
||||||
|
- Access to build service or local Docker environment
|
||||||
|
|
||||||
|
### Build and Install
|
||||||
|
|
||||||
|
1. **Build the package**:
|
||||||
|
```bash
|
||||||
|
cloudron build --set-build-service builder.docker.due.ren \
|
||||||
|
--build-service-token e3265de06b1d0e7bb38400539012a8433a74c2c96a17955e \
|
||||||
|
--set-repository andreasdueren/keila-cloudron \
|
||||||
|
--tag 0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Install on Cloudron**:
|
||||||
|
```bash
|
||||||
|
cloudron install --location keila.yourdomain.com \
|
||||||
|
--image andreasdueren/keila-cloudron:0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Local Development Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone this repository
|
||||||
|
git clone <repository-url>
|
||||||
|
cd keila-cloudron
|
||||||
|
|
||||||
|
# Build locally
|
||||||
|
cloudron build
|
||||||
|
|
||||||
|
# Install for testing
|
||||||
|
cloudron install --location keila.local.dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Default Settings
|
||||||
|
|
||||||
|
- **Admin Account**: `admin@yourdomain.com` (password in `/app/data/root_credentials`)
|
||||||
|
- **Database**: PostgreSQL via Cloudron addon
|
||||||
|
- **Email**: Configured via Cloudron SMTP service
|
||||||
|
- **Registration**: Disabled by default for security
|
||||||
|
- **Port**: 4000 (proxied via nginx)
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
The following Cloudron environment variables are automatically configured:
|
||||||
|
|
||||||
|
- `CLOUDRON_POSTGRESQL_URL` - Database connection
|
||||||
|
- `CLOUDRON_MAIL_SMTP_*` - Email configuration
|
||||||
|
- `CLOUDRON_APP_DOMAIN` - Application domain
|
||||||
|
- `CLOUDRON_MAIL_FROM` - From email address
|
||||||
|
|
||||||
|
## Data Persistence
|
||||||
|
|
||||||
|
- **Application Data**: `/app/data/keila` - Keila installation
|
||||||
|
- **Uploads**: `/app/data/uploads` - User-uploaded content
|
||||||
|
- **Credentials**: `/app/data/root_credentials` - Admin login info
|
||||||
|
- **Secrets**: `/app/data/secret_key_base` - Application secret
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **Database Connection**: Ensure PostgreSQL addon is properly configured
|
||||||
|
2. **Email Sending**: Verify Cloudron SMTP settings in mail addon
|
||||||
|
3. **File Permissions**: All files should be owned by `cloudron:cloudron`
|
||||||
|
|
||||||
|
### Logs
|
||||||
|
|
||||||
|
View application logs:
|
||||||
|
```bash
|
||||||
|
cloudron logs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reset Admin Password
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Access the container
|
||||||
|
cloudron exec
|
||||||
|
|
||||||
|
# Check current credentials
|
||||||
|
cat /app/data/root_credentials
|
||||||
|
|
||||||
|
# Reset if needed (restart required)
|
||||||
|
rm /app/data/root_credentials
|
||||||
|
exit
|
||||||
|
cloudron restart
|
||||||
|
```
|
||||||
|
|
||||||
|
## Technical Details
|
||||||
|
|
||||||
|
### Architecture
|
||||||
|
|
||||||
|
- **Base Image**: `cloudron/base:4.2.0`
|
||||||
|
- **Runtime**: Elixir 1.15 with Phoenix framework
|
||||||
|
- **Database**: PostgreSQL (via Cloudron addon)
|
||||||
|
- **Web Server**: Nginx reverse proxy
|
||||||
|
- **Process Manager**: Direct Elixir application startup
|
||||||
|
|
||||||
|
### Security Features
|
||||||
|
|
||||||
|
- User registration disabled by default
|
||||||
|
- Security headers configured in nginx
|
||||||
|
- File upload restrictions
|
||||||
|
- Database connection over SSL
|
||||||
|
- Secret key auto-generation
|
||||||
|
|
||||||
|
### File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
/app/code/ # Application code (read-only)
|
||||||
|
/app/data/keila/ # Keila installation
|
||||||
|
/app/data/uploads/ # User uploads
|
||||||
|
/app/data/ # Persistent data
|
||||||
|
```
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
- **Keila Documentation**: https://www.keila.io/docs
|
||||||
|
- **Keila GitHub**: https://github.com/pentacent/keila
|
||||||
|
- **Cloudron Docs**: https://docs.cloudron.io
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
- **Keila**: AGPLv3 License
|
||||||
|
- **This Package**: MIT License
|
79
nginx.conf
Normal file
79
nginx.conf
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
server {
|
||||||
|
listen 4000 default_server;
|
||||||
|
listen [::]:4000 default_server;
|
||||||
|
|
||||||
|
server_name _;
|
||||||
|
root /tmp;
|
||||||
|
|
||||||
|
client_max_body_size 100m;
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
add_header X-Frame-Options SAMEORIGIN;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header Referrer-Policy strict-origin-when-cross-origin;
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
access_log /dev/stdout;
|
||||||
|
error_log /dev/stderr;
|
||||||
|
|
||||||
|
# Gzip compression
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_proxied any;
|
||||||
|
gzip_comp_level 6;
|
||||||
|
gzip_types
|
||||||
|
text/plain
|
||||||
|
text/css
|
||||||
|
text/xml
|
||||||
|
text/javascript
|
||||||
|
application/json
|
||||||
|
application/javascript
|
||||||
|
application/xml+rss
|
||||||
|
application/atom+xml
|
||||||
|
image/svg+xml;
|
||||||
|
|
||||||
|
# Proxy to Keila application
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:4001;
|
||||||
|
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_cache_bypass $http_upgrade;
|
||||||
|
proxy_redirect off;
|
||||||
|
|
||||||
|
# Timeout settings
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_send_timeout 60s;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Health check endpoint
|
||||||
|
location /healthz {
|
||||||
|
proxy_pass http://127.0.0.1:4001/healthz;
|
||||||
|
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;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Static files caching
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
proxy_pass http://127.0.0.1:4001;
|
||||||
|
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 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
}
|
5
robots.txt
Normal file
5
robots.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow: /admin/
|
||||||
|
Disallow: /api/
|
||||||
|
Disallow: /auth/
|
||||||
|
Allow: /
|
68
start.sh
Normal file
68
start.sh
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
echo "Starting Keila on Cloudron"
|
||||||
|
|
||||||
|
# Copy Keila release to /app/data on first run
|
||||||
|
if [[ ! -d "/app/data/keila" ]]; then
|
||||||
|
echo "==> Initializing Keila installation"
|
||||||
|
cp -r /tmp/keila-release /app/data/keila
|
||||||
|
chown -R cloudron:cloudron /app/data/keila
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate secret key base if not exists
|
||||||
|
if [[ ! -f "/app/data/secret_key_base" ]]; then
|
||||||
|
echo "==> Generating secret key base"
|
||||||
|
openssl rand -hex 64 > /app/data/secret_key_base
|
||||||
|
chown cloudron:cloudron /app/data/secret_key_base
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
export SECRET_KEY_BASE=$(cat /app/data/secret_key_base)
|
||||||
|
export DB_URL="${CLOUDRON_POSTGRESQL_URL}"
|
||||||
|
export URL_HOST="${CLOUDRON_APP_DOMAIN}"
|
||||||
|
export URL_SCHEMA="https"
|
||||||
|
export URL_PORT="443"
|
||||||
|
export PORT="4000"
|
||||||
|
|
||||||
|
# Configure SMTP
|
||||||
|
export MAILER_SMTP_HOST="${CLOUDRON_MAIL_SMTP_SERVER}"
|
||||||
|
export MAILER_SMTP_PORT="${CLOUDRON_MAIL_SMTP_PORT}"
|
||||||
|
export MAILER_SMTP_USERNAME="${CLOUDRON_MAIL_SMTP_USERNAME}"
|
||||||
|
export MAILER_SMTP_PASSWORD="${CLOUDRON_MAIL_SMTP_PASSWORD}"
|
||||||
|
export MAILER_SMTP_FROM_EMAIL="${CLOUDRON_MAIL_FROM}"
|
||||||
|
|
||||||
|
# Set user content directory
|
||||||
|
export USER_CONTENT_DIR="/app/data/uploads"
|
||||||
|
mkdir -p /app/data/uploads
|
||||||
|
chown cloudron:cloudron /app/data/uploads
|
||||||
|
|
||||||
|
# Disable registration for security (admin can create users)
|
||||||
|
export DISABLE_REGISTRATION="true"
|
||||||
|
|
||||||
|
# Set database pool size
|
||||||
|
export DATABASE_POOL_SIZE="10"
|
||||||
|
|
||||||
|
# Create root user credentials file if not exists
|
||||||
|
if [[ ! -f "/app/data/root_credentials" ]]; then
|
||||||
|
echo "==> Generating root user credentials"
|
||||||
|
ROOT_PASSWORD=$(openssl rand -base64 32)
|
||||||
|
echo "Email: admin@${CLOUDRON_APP_DOMAIN}" > /app/data/root_credentials
|
||||||
|
echo "Password: ${ROOT_PASSWORD}" >> /app/data/root_credentials
|
||||||
|
export ROOT_EMAIL="admin@${CLOUDRON_APP_DOMAIN}"
|
||||||
|
export ROOT_PASSWORD="${ROOT_PASSWORD}"
|
||||||
|
chown cloudron:cloudron /app/data/root_credentials
|
||||||
|
chmod 600 /app/data/root_credentials
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Starting nginx"
|
||||||
|
nginx -t
|
||||||
|
nginx
|
||||||
|
|
||||||
|
echo "==> Running database migrations"
|
||||||
|
cd /app/data/keila
|
||||||
|
sudo -u cloudron -E /app/data/keila/bin/keila eval "Keila.Release.migrate()"
|
||||||
|
|
||||||
|
echo "==> Starting Keila application"
|
||||||
|
cd /app/data/keila
|
||||||
|
exec sudo -u cloudron -E /app/data/keila/bin/keila start
|
Reference in New Issue
Block a user