diff --git a/.github/workflows/build_install_folder.yml b/.github/workflows/build_install_folder.yml new file mode 100644 index 00000000..936cd10f --- /dev/null +++ b/.github/workflows/build_install_folder.yml @@ -0,0 +1,24 @@ +name: Build Deployment Zip + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Create deployment ZIP + run: | + zip -r deploy_bundle.zip \ + install/ \ + + - name: Release + uses: softprops/action-gh-release@v2 + with: + files: deploy_bundle.zip diff --git a/README.md b/README.md index 4b0e703a..56606c53 100644 --- a/README.md +++ b/README.md @@ -101,3 +101,69 @@ sudo chown -R $(whoami): ${APP_NAME} ``` From here on you can follow the steps on the [Getting Started](https://docs.decidim.org/en/install/) guide. + +## Using a production deploy script + +We've been working on a script that you can use to have a fully functional, production-ready decidim instance. + +```bash +curl -fsSL https://decidim.org/install | bash +``` + +It will install the necessary tools to make decidim work on your server. + +- Docker +- unzip +- UFW + +The application will be hosted in the `/opt/decidim` directory by default, even though you can change it with `REPOSITORY_PATH` environment variable. + +## App - Main Decidim Web Application +The app itself will be the container with the base image you decide (By default is the latest Decidim version: `decidim/decidim:latest`). You can change it with the `DECIDIM_IMAGE` environment variable. + +This is the front-end web process users access in the browser. + +## Worker +The worker will be the one responsible for all the background jobs that the application needs to run. + +## Cache +The app needs a cache server. This will be a `redis:8-alpine` instance. This cache will be used both by the app and the worker. + +## Database + +The application needs a database to run. Through the installation process you will be asked if you have an already working database, if not, you will have a postgres container with all the schema and migrations run (It will be a `postgres:17-alpine`) + +## Configuration + +To configure the application you will have to answer some questions that will, at the end, generate a `.env` file. + +### Environment Variables Reference + +To see the full list of Decidim Environment Variables, and that you can add to your generated `.env` file, you can take a look at the official [documentation](https://docs.decidim.org/en/develop/configure/environment_variables) + +| Variable | Default | Used In | Description | +|----------|---------|---------|-------------| +| **BUNDLE_GEMFILE** | `Gemfile.wrapper` | app, worker | Selects which Gemfile the container should use. | +| **DECIDIM_IMAGE** | `decidim/decidim:latest` | app, worker | Overrides the Decidim Docker image version. | +| **DECIDIM_DOMAIN** | — | app, traefik | Domain for HTTPS routing and URL generation. | +| **SECRET_KEY_BASE** | — | app, worker | Rails secret key used for sessions and cookies. | +| **DATABASE_NAME** | `decidim` | db | PostgreSQL database name. | +| **DATABASE_USER** | `decidim` | db | PostgreSQL username. | +| **DATABASE_HOST** | `db` | app, worker | Hostname of your PostgreSQL instance. | +| **DATABASE_PASSWORD** | `decidim` | db | PostgreSQL user password. | +| **DATABASE_URL** | — | app, worker | Full PostgreSQL connection URL (overrides other DB vars). | +| **SMTP_USERNAME** | — | app, worker | Username for SMTP authentication. | +| **SMTP_PASSWORD** | — | app, worker | Password for SMTP authentication. | +| **SMTP_ADDRESS** | — | app, worker | SMTP server hostname. | +| **SMTP_DOMAIN** | — | app, worker | SMTP domain. | +| **SMTP_PORT** | — | app, worker | SMTP port. | +| **SMTP_STARTTLS_AUTO** | `true` | app | Enables STARTTLS automatically. | +| **REDIS_URL** | `redis://decidim_cache:6379/0` | app | Redis URL for cache + sessions. | +| **VAPID_PUBLIC_KEY** | — | app | Web Push public key for browser notifications. | +| **VAPID_PRIVATE_KEY** | — | app | Web Push private key (keep secret). | +| **CERTIFICATE_EMAIL** | — | traefik | Email used by Let's Encrypt for certificate issues/renewals. | +| **WEB_CONCURRENCY** | `2` | app | Puma concurrency setting. | +| **LOG_LEVEL** | `info` | app | Log level for Rails. | +| **DECIDIM_FORCE_SSL** | `false` | app | Enforce HTTPS-only traffic. | +| **MAPS_API_KEY** | — | app | API key for maps provider. | +| **MAPS_PROVIDER** | `here` | app | Selects map provider (here, mapbox, google, etc). | diff --git a/install/README.md b/install/README.md new file mode 100644 index 00000000..5edda7e9 --- /dev/null +++ b/install/README.md @@ -0,0 +1,451 @@ +# Decidim Installation Guide 🗳️ + +This guide will help you install Decidim on your own server, even with minimal technical knowledge. We'll walk through everything from setting up a server to launching your democracy platform. + +## 📋 Table of Contents + +1. [Prerequisites](#prerequisites) +2. [Step 1: Create a Server](#step-1-create-a-server) +3. [Step 2: Connect to Your Server](#step-2-connect-to-your-server) +4. [Step 3: Configure DNS](#step-3-configure-dns) +5. [Step 4: Install Decidim](#step-4-install-decidim) +6. [Step 5: Configure Email (SMTP)](#step-5-configure-email-smtp) +7. [Step 6: Security & Firewall Setup](#step-6-security--firewall-setup) +8. [Step 7: Complete Setup](#step-7-complete-setup) +8. [Troubleshooting](#troubleshooting) + +--- + +## Prerequisites + +Before you start, you'll need: + +- **A domain name** (like `example.org`) - you can buy one from any domain registrar +- **Patience** - the installation takes about 20-30 minutes + +### Server Requirements + +**Minimum specifications:** +- **RAM**: 2GB minimum (4GB+ recommended for production) +- **Storage**: 20GB+ +- **OS**: Ubuntu 24.04 (required) + +**Recommended providers:** +- **Hetzner** - Used in this guide +- **Here Maps** - For geolocation features +- **SMTP Email Provider** - For sending emails (Gmail, Scaleway, Rapidmail, etc.) + +--- + +## Step 1: Create a Server + +We recommend using Hetzner for affordable, reliable hosting. Here's how to set up a server: + +### 1.1 Create a Hetzner Account + +1. Go to [hetzner.com](https://hetzner.com) +2. Click "Register" and create an account + +This process might take some time until Hetzner verifies your account. + +### 1.2 Create a New Server + +1. Log into your Hetzner account +2. Click "Servers" → "Create Server" +3. **Server Location**: Choose a location near your users +4. **Server Type**: + - Click "Shared" (cheaper option, perfect for small organizations) + - Choose "CAX21" +5. **Image**: Select **Ubuntu 24.04** (important! or a newer LTS if available) +6. **SSH Key** (Recommended): + - Create SSH key if you don't have one + - If unsure, skip this and use password +7. **Server Name**: Give it a name like "decidim-server" +8. Click "Create & Buy Now" + +**How to create an SSH key (if needed)**: + +If you don't have an SSH key, create one on your local machine: + + ```bash +ssh-keygen -t rsa -b 4096 -C "your_email@example.com" + ``` + +This will generate a public/private key pair. Copy the contents of `~/.ssh/id_rsa.pub` and paste it into Hetzner's SSH key field. + +### 1.3 Wait for Server to be Ready + +Your server will be ready in 1-2 minutes. You'll see: +- Server IP address (e.g., `123.45.67.89`) +- Root password (if you chose password instead of SSH key) + +**Save this information! You'll need it immediately.** + +--- + +## Step 2: Connect to Your Server + +### Option A: Using SSH Key (More Secure) + +If you created an SSH key: +1. Open your terminal (Terminal on Mac, PowerShell on Windows) +2. Type: `ssh root@YOUR_SERVER_IP` +3. Replace `YOUR_SERVER_IP` with your actual IP address + +### Option B: Using Password (Easier) + +1. Open your terminal (Terminal on Mac, PowerShell on Windows) +2. Type: `ssh root@YOUR_SERVER_IP` +3. When prompted for password, paste the root password from Hetzner +4. It won't show characters while typing - that's normal! + +**First time only**: You'll see a warning about "authenticity of host can't be established". Type `yes` and press Enter. + +--- + +## Step 3: Configure DNS + +Before installing Decidim, you need to point your domain to your server. + +### 3.1 Find Your Server's IP Address + +If you lost it, you can find it in the Hetzner dashboard for that server. + +### 3.2 Update DNS Settings + +Go to where you bought your domain (Namecheap, GoDaddy, etc.) and add these DNS records: + +| Type | Host/Name | Value | TTL | +|------|-----------|-------|-----| +| A | @ | YOUR_SERVER_IP | auto | +| CNAME | www | @ | auto | + +**Example**: If your server IP is `123.45.67.89` and your domain is `example.org` and you want the platform to be accessible in `decidim.example.org`, you would set: +- A record: `decidim.example.org` → `123.45.67.89` + +### 3.3 Wait for DNS Propagation + +DNS changes take 5-30 minutes to work worldwide. You can check if it's ready: +```bash +ping decidim.example.org +``` + +--- + +## Step 4: Install Decidim + +Now for the main installation! Run these commands one by one on your server. + +### 4.1 Download and Run the Installer + +```bash +curl -fsSL https://decidim.org/install | bash +``` + +### 4.2 Follow the Prompts + +The installer will ask for: + +**Instance Information:** +- **Organization Name**: e.g., "City Hall Democracy Platform" +- **Domain**: e.g., `decidim.example.org` (must match your DNS setup) + +**Database Configuration:** +- **Local Database** (Recommended): PostgreSQL with auto-generated credentials +- **External Database**: Only if you have your own database server + +**Important Database Notes:** +- The installer creates a secure database user with random password +- Database URL is stored in `/opt/decidim/.env` file +- For production, consider regular backups of PostgreSQL + +**File Storage:** +- **Local Storage** (Default): Perfect for most users +- **S3 Storage**: Only if you use Amazon S3 + +**Configuration Files Generated:** +- `.env`: Contains all your configuration (database, SMTP, secrets) +- `docker-compose.yml`: Defines services and networks +- **Important**: Never commit `.env` to version control - it contains passwords! + +**Email Configuration** (Step 5 covers this in detail) + +**SSL Certificate**: The installer will automatically set up free SSL certificates + +--- + +## Step 5: Configure Email (SMTP) + +Email is crucial for user notifications and password resets. You'll need an SMTP provider. + +### 5.1 Choose an Email Provider + +**Free Options** +- [Gmail SMTP](https://support.google.com/a/answer/176600) (500 emails/day limit) + +**Paid Options** +- [Scaleway](https://www.scaleway.com/en/transactional-email-tem/) +- [Mailgun](https://mailgun.com) + +### 5.2 Get SMTP Settings + +Each provider will give you: +- **SMTP Server**: e.g., `smtp.sendgrid.net` +- **Port**: e.g., `587` +- **Username**: Your email or API key +- **Password**: Your password or API key +- **From Address**: e.g., `noreply@decidim.example.org` + +### 5.3 Configure SMTP during Installation + +When the installer asks for email settings, enter: +- **SMTP Host**: Your provider's SMTP server +- **SMTP Port**: 587 (most common) +- **SMTP Username**: Your SMTP username +- **SMTP Password**: Your SMTP password +- **From Email**: noreply@decidim.example.org +- **From Name**: Your Organization Name + +--- + +## Step 6: Security & Firewall Setup + +### 6.1 Firewall Configuration + +The installer will configure firewall rules automatically. You can check the status: + +```bash +# Check firewall status +sudo ufw status + +# Allow SSH (don't lock yourself out!) +sudo ufw allow ssh + +# Enable firewall if not already active +sudo ufw enable +``` + +### 6.2 SSL Certificate (Automatic) + +The installer uses Traefik to handle SSL certificates automatically through Let's Encrypt: +- **Automatic renewal**: Certificates renew themselves +- **No manual intervention needed** +- **HTTPS enforced**: All traffic redirected to secure connections + +If you experience SSL issues: +- Ensure your domain correctly points to the server IP +- Wait 5-10 minutes for DNS propagation +- Check that ports 80 and 443 are accessible from the internet + +### 6.3 Security Best Practices + +Based on the traditional Decidim setup experience: + +1. **Never expose database**: Use firewalls and network segmentation +2. **Keep software updated**: Run updates regularly +3. **Use strong passwords**: For admin users and database +4. **Monitor logs**: Check for suspicious activity +5. **Backup regularly**: Database and configuration files + +### 6.3 Email Domain Authentication + +For better email deliverability, configure these DNS records (advanced): + +- **SPF Record**: `v=spf1 include:_spf.google.com ~all` (if using Gmail) +- **DKIM**: Generate keys from your email provider +- **DMARC**: `v=DMARC1; p=quarantine; rua=mailto:dmarc@decidim.example.org` + +## Step 7: Complete Setup + +### 7.1 Create System Administrator + +During installation, you'll be prompted to create a system admin: +- **Email**: Use your admin email +- **Password**: The installer will auto-generate a secure password +- **Save the password!** You'll need it to log in + +### 7.2 Access Your Decidim Instance + +1. Open your web browser +2. Go to `https://decidim.example.org/system` +3. Log in with: + - Email: Your system admin email + - Password: The password shown during installation + +### 7.3 Configure Your Organization + +Once logged in, you'll need to: +1. Set up your organization details +2. Create your first participatory space +3. Configure user registration settings + +### 7.4 Background Jobs & Maintenance + +The Docker setup includes automatic background job processing using Sidekiq. Here's what's running: + +**Background Processing**: +- Sidekiq handles email sending and other background tasks +- Automatically restarts if it crashes +- Monitored and managed through Docker Compose + +**To manually check Sidekiq jobs:** +```bash +# Check Sidekiq status +docker compose logs worker + +# Restart Sidekiq if needed +docker compose restart sidekiq +``` + +--- + +## 🔧 Useful Commands + +### Managing Your Decidim Instance + +```bash +# Go to the Decidim directory +cd /opt/decidim + +# View live logs +docker compose logs -f + +# Stop Decidim +docker compose down + +# Start Decidim +docker compose up -d + +# Restart services +docker compose restart + +# Check service status +docker compose ps +``` + +### Updating Decidim + +```bash +cd /opt/decidim +git pull +docker compose pull +docker compose up -d +``` + +--- + +## Troubleshooting + +### Common Issues + +**"Connection refused" when connecting to server:** +- Wait 2-3 minutes after server creation +- Check that you're using the correct IP address +- Try `ping YOUR_SERVER_IP` first + +**DNS not working:** +- Wait at least 30 minutes after changing DNS records +- Use `dig example.org` to check DNS +- Make sure A records point to your server IP +- Check records + +**Email not sending:** +- Double-check SMTP settings in `/opt/decidim/.env` +- Verify your firewall allows port 587 outbound +- Check with your email provider about authentication +- **Gmail issues**: May need "App Password" if 2FA enabled +- Check for IPv6 conflicts (installer handles this automatically) + +**Installation fails:** +- Run `./install.sh` again +- Check the error message carefully +- Check available disk space +- Verify internet connection + +**Performance issues on low-memory servers:** +- **Memory optimization**: Consider upgrading to 4GB RAM for production +- **Monitor memory**: `free -h` to check usage +- **Check Docker resource limits**: `docker stats` + +**SSL Certificate problems:** +- Domain must resolve to server IP before certificate issuance +- Port 80 and 443 must be accessible from internet +- Check Traefik logs: `docker compose logs traefik` +- Wait 5-10 minutes for certificate issuance + +### Getting Help + +- **Documentation**: [docs.decidim.org](https://docs.decidim.org) +- **Installation Issues**: [GitHub Issues](https://github.com/decidim/docker/issues) +- **Community**: [Decidim Community Forum](https://meta.decidim.org) +- **Alternative Installation**: [Platoniq Manual Guide](https://platoniq.github.io/decidim-install/) (comprehensive traditional setup) + +## 🎯 Advanced Configuration Options + +### Geolocation & Maps + +For mapping features (meeting locations, proposals with addresses): + +1. **Get HERE Maps API Key**: + - Register at [HERE Developer Portal](https://developer.here.com/) + - Create free account and get API credentials + +2. **Configure in Decidim**: + ```bash + # Edit environment file + nano /opt/decidim/.env + # Add: + # MAPS_API_KEY=your-here-api-key + # MAPS_PROVIDER=here + ``` + +3. **Restart services**: + ```bash + docker compose restart + ``` + +### Important Files + +After installation, your configuration is stored in: +- `/opt/decidim/.env` - **All your settings** (database, email, secrets) 🔐 +- `/opt/decidim/docker-compose.yml` - Service definitions +- `/opt/decidim/storage/` - Persistent data (database, uploads, logs) + +**🚨 Security Warning**: +- **Never commit `.env` to version control** +- **Keep backup of `.env` file in secure location** +- **Contains database passwords, SMTP credentials, and secret keys** + +### Log Locations + +For troubleshooting, check these logs: +```bash +# Application logs +docker compose logs -f decidim + +# Database logs +docker compose logs -f db + +# All services +docker compose logs -f +``` + +--- + +## 🎉 Congratulations! + +You now have a fully functional Decidim instance running on your own server! + +Your democracy platform is ready to: +- Accept user registrations +- Host discussions and debates +- Run participatory budgeting processes +- Enable collaborative decision-making + +Remember to: +- Regularly update your server (`apt update && apt upgrade`) +- Back up your data +- Monitor your email deliverability +- Engage with your community! + +Happy democracy building! 🗳️✨ diff --git a/install/config/sidekiq.yml b/install/config/sidekiq.yml new file mode 100644 index 00000000..c9e659c4 --- /dev/null +++ b/install/config/sidekiq.yml @@ -0,0 +1,16 @@ +:concurrency: <%= ENV.fetch("SIDEKIQ_CONCURRENCY", 5) %> +:queues: + - [mailers, 4] + - [vote_reminder, 2] + - [reminders, 2] + - [default, 2] + - [newsletter, 2] + - [newsletters_opt_in, 2] + - [conference_diplomas, 2] + - [events, 2] + - [translations, 2] + - [user_report, 2] + - [block_user, 2] + - [metrics, 1] + - [exports, 1] + - [close_meeting_reminder, 1] diff --git a/install/dependencies/build_env.sh b/install/dependencies/build_env.sh new file mode 100644 index 00000000..fc78f5d8 --- /dev/null +++ b/install/dependencies/build_env.sh @@ -0,0 +1,277 @@ +#!/bin/bash +set -e +set -u +set -o pipefail + +if [ -z "${REPOSITORY_PATH:-}" ]; then + echo "❌ Error: REPOSITORY_PATH is not set" + exit 1 +fi + +BUILD_ENV_PATH="$REPOSITORY_PATH/.env" + +COMPOSE_PROFILES="" + +echo "───────────────────────────────────────────────" +echo "🔧 Environment Configuration Phase" +echo " We'll now collect all the information needed to configure your Decidim instance." +echo " All responses will be saved in a .env file that you can edit later." +echo +echo "📝 Information we'll collect:" +echo " • Instance details (name, domain)" +echo " • Database settings (local PostgreSQL or external)" +echo " • Email configuration (SMTP server)" +echo " • File storage (local filesystem or S3 bucket)" +echo " • Security keys (auto-generated)" +echo +echo "💡 Don't worry if you don't have all the details ready!" +echo " You can always modify the .env file after installation." +echo +echo "Press Enter to continue..." +read -r "$BUILD_ENV_PATH" <>"$BUILD_ENV_PATH" </dev/null 2>&1; then + echo "🐳 Docker not found. Installing Docker..." + echo "⚠️ After installation, you'll need to re-run this script for changes to take effect." + echo "💡 You can run 'newgrp docker' to activate Docker group membership." + + if ! curl -fsSL https://get.docker.com | bash; then + echo "❌ Failed to install Docker" + exit 1 + fi + + if ! sudo usermod -aG docker "${USER}"; then + echo "❌ Failed to add user to Docker group" + exit 1 + fi + + echo "" + echo "🔄 Docker installation completed!" + echo "📋 Next steps:" + echo " 1. Log out and log back in, OR run: 'newgrp docker'" + echo " 2. Re-run this installation script" + echo "" + echo "⏹️ Exiting for user session refresh..." + exit 1 +else + echo "✅ Docker is installed: $(docker --version)" + + # Check if user can run docker commands + if ! docker info >/dev/null 2>&1; then + echo "⚠️ Docker is installed but current user cannot run Docker commands." + echo "💡 Try running: 'newgrp docker' or log out and log back in." + echo " If that doesn't work, you may need to: 'sudo usermod -aG docker \$USER'" + exit 1 + fi + + echo "✅ Docker is accessible for current user" +fi diff --git a/install/dependencies/create_system_admin.sh b/install/dependencies/create_system_admin.sh new file mode 100644 index 00000000..4296aa03 --- /dev/null +++ b/install/dependencies/create_system_admin.sh @@ -0,0 +1,45 @@ +#!/bin/bash +set -e +set -u +set -o pipefail + +generate_system_admin() { + read -r -p "email: " SYSTEM_EMAIL /dev/null; do + echo "Waiting for Rails server to start..." + sleep 10 +done + +echo "Container is running correctly... Now we are going to create the system admin." + +generate_system_admin + +if [ $? -eq 1 ]; then + echo "❌ Seems like there was a problem creating the system admin." + echo + echo "🔧 Troubleshooting:" + echo " • Try running the command manually:" + echo " docker exec -ti decidim bin/rails decidim_system:create_admin" + echo " • Review the logs for any errors:" + echo " docker compose logs decidim" +else + echo "✅ System administrator created successfully!" + echo "Your password to access is: ${SYSTEM_PASSWORD}" + echo "📍 You can now access the admin panel at: https://${DECIDIM_DOMAIN}/system" +fi diff --git a/install/dependencies/decidim_version.sh b/install/dependencies/decidim_version.sh new file mode 100644 index 00000000..f8f29296 --- /dev/null +++ b/install/dependencies/decidim_version.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +echo "───────────────────────────────────────────────" +echo "📦 Decidim version" +echo +echo "💡 About Decidim versions:" +echo " • latest - Most recent stable release (recommended)" +echo " • Custom images - Your own modified Decidim builds" +echo +echo "If you want, later on, you can modify the 'docker-compose.yml' to change the Decidim version" +echo +echo "Default image: decidim/decidim:latest" +echo + +while true; do + read -r -p "👉 Click Enter to continue with the download of the Decidim image" Gemfile.wrapper <Gemfile.local <>Gemfile.local +fi diff --git a/install/dependencies/generate_vapid_keys.sh b/install/dependencies/generate_vapid_keys.sh new file mode 100644 index 00000000..2b045dd2 --- /dev/null +++ b/install/dependencies/generate_vapid_keys.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +set -e +set -u +set -o pipefail + +echo "🔐 Generating VAPID keys..." + +# Check if DECIDIM_IMAGE is set +if [ -z "${DECIDIM_IMAGE:-}" ]; then + echo "❌ Error: DECIDIM_IMAGE is not set" + exit 1 +fi + +output=$(docker run --rm \ + "$DECIDIM_IMAGE" \ + bin/rails decidim:pwa:generate_vapid_keys) + +echo "✅ The VAPID keys have been generated correctly" + +VAPID_PUBLIC_KEY=$(echo "$output" | grep 'VAPID_PUBLIC_KEY' | cut -d'=' -f2) +VAPID_PRIVATE_KEY=$(echo "$output" | grep 'VAPID_PRIVATE_KEY' | cut -d'=' -f2) + +# Export the keys for use by calling script +export VAPID_PUBLIC_KEY +export VAPID_PRIVATE_KEY + +echo "🔑 Keys successfully extracted!" diff --git a/install/dependencies/open_ports.sh b/install/dependencies/open_ports.sh new file mode 100644 index 00000000..fce59011 --- /dev/null +++ b/install/dependencies/open_ports.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +open_ports() { + echo + echo "To handle the SSL certificate we will have to open the port 80 and the port 443" + echo + + if ! command -v ufw; then + echo "UFW nos intalled. We are going to install it to allow openning ports 80 and 443 on this machine." + sudo apt install ufw + fi + + sudo ufw allow 22 + sudo ufw allow 80 + sudo ufw allow 443 + sudo ufw --force enable +} + +echo "───────────────────────────────────────────────" +echo "Now we are going to open the necessary ports for Decidim to work ussing UFW." +echo "This is a standard practice to protect your server." +echo +read -r -p "Can we proceed openning ports 22, 80 and 443? [Y/n] " yn /dev/null | grep -Eq "Ubuntu|Debian"; then + echo "This installation process must be run on a Debian/Ubuntu distribution." + exit 1 +fi + +echo "✅ Correct distribution." diff --git a/install/docker-compose.yml b/install/docker-compose.yml new file mode 100644 index 00000000..21b0cfa8 --- /dev/null +++ b/install/docker-compose.yml @@ -0,0 +1,129 @@ +services: + app: + container_name: decidim + image: ${DECIDIM_IMAGE:-decidim/decidim:latest} + command: ["bin/rails", "server", "-b", "0.0.0.0"] + entrypoint: ["/code/entrypoint.sh"] + restart: always + depends_on: + - cache + expose: + - 3000 + volumes: + - ${PWD}/Gemfile.wrapper:/code/Gemfile.wrapper + - ${PWD}/Gemfile.local:/code/Gemfile.local + - ${PWD}/scripts/entrypoint.sh:/code/entrypoint.sh + - app_gems:/usr/local/bundle + - storage_data:/code/storage + - migrations_data:/code/db/migrate + labels: + - "traefik.enable=true" + - "traefik.http.routers.app.rule=Host(`$DECIDIM_DOMAIN`)" + - "traefik.http.routers.app.entrypoints=websecure" + - "traefik.http.routers.app.tls=true" + - "traefik.http.routers.app.tls.certresolver=myresolver" + - "traefik.http.services.app.loadbalancer.server.port=3000" + env_file: + - .env + environment: + - BUNDLE_GEMFILE=Gemfile.wrapper + - DATABASE_URL + - SECRET_KEY_BASE + - DECIDIM_FORCE_SSL=${DECIDIM_FORCE_SSL:-false} + - REDIS_URL=${REDIS_URL:-redis://decidim_cache:6379/0} + - WEB_CONCURRENCY=${WEB_CONCURRENCY:-2} + - LOG_LEVEL=${LOG_LEVEL:-info} + - DECIDIM_ENABLE_HTML_HEADER_SNIPPETS + - SMTP_STARTTLS_AUTO=${SMTP_STARTTLS_AUTO:-true} + - SMTP_USERNAME + - SMTP_PASSWORD + - SMTP_ADDRESS + - SMTP_DOMAIN + - SMTP_PORT + - DECIDIM_MAILER_SENDER + - MAPS_API_KEY + - MAPS_PROVIDER=${MAPS_PROVIDER:-here} + worker: + image: ${DECIDIM_IMAGE:-decidim/decidim:latest} + container_name: decidim_worker + command: ["bundle", "exec", "sidekiq", "-C", "config/sidekiq.yml"] + entrypoint: ["/code/sidekiq_entrypoint.sh"] + pull_policy: always + restart: always + env_file: + - .env + volumes: + - ${PWD}/Gemfile.wrapper:/code/Gemfile.wrapper + - ${PWD}/Gemfile.local:/code/Gemfile.local + - ${PWD}/scripts/sidekiq_entrypoint.sh:/code/sidekiq_entrypoint.sh + - ${PWD}/scripts/config/sidekiq.yml:/code/config/sidekiq.yml + - worker_gems:/usr/local/bundle + - storage_data:/code/storage + - migrations_data:/code/db/migrate + environment: + - BUNDLE_GEMFILE + - DATABASE_URL + - SECRET_KEY_BASE + - DECIDIM_FORCE_SSL=false + - QUEUE_ADAPTER=sidekiq + - REDIS_URL=${REDIS_URL:-redis://decidim_cache:6379/0} + - SMTP_USERNAME + - SMTP_PASSWORD + - SMTP_ADDRESS + - SMTP_DOMAIN + - SMTP_PORT + - DECIDIM_MAILER_SENDER + links: + - cache + traefik: + image: traefik:v3.6 + container_name: traefik + command: + - --api + - --providers.docker=true + - --log.level=DEBUG + - --entrypoints.web.address=:80 + - --entrypoints.websecure.address=:443 + - --entrypoints.traefik.address=:8080 + - --entrypoints.web.http.redirections.entryPoint.to=websecure + - --entrypoints.web.http.redirections.entryPoint.scheme=https + - --certificatesresolvers.myresolver.acme.email=${CERTIFICATE_EMAIL} + - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json + - --certificatesresolvers.myresolver.acme.httpchallenge=true + - --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web + ports: + - "80:80" + - "443:443" + restart: unless-stopped + volumes: + - traefik_data:/letsencrypt + - "/var/run/docker.sock:/var/run/docker.sock:ro" + labels: + - "traefik.enable=true" + - "traefik.http.routers.traefik.service=api@internal" + db: + image: postgres:17-alpine + container_name: decidim_db + profiles: ["db"] + env_file: + - .env + environment: + POSTGRES_USER: ${DATABASE_USER:-decidim} + POSTGRES_PASSWORD: ${DATABASE_PASSWORD:-decidim} + POSTGRES_DB: ${DATABASE_NAME:-decidim} + volumes: + - pg_data:/var/lib/postgresql/data + cache: + image: redis:8-alpine + container_name: decidim_cache + volumes: + - cache_data:/data + restart: always +volumes: + app_gems: {} + worker_gems: {} + pg_data: {} + cache_data: {} + storage_data: {} + migrations_data: {} + traefik_data: {} diff --git a/install/install.sh b/install/install.sh new file mode 100644 index 00000000..bc9fdf50 --- /dev/null +++ b/install/install.sh @@ -0,0 +1,152 @@ +#!/bin/bash +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +set -e +set -u +set -o pipefail + +echo -e "***********************************************************************" +echo -e "* 🚀 Welcome to Decidim Installation Script! *" +echo -e "* *" +echo -e "* This script will install Decidim on this machine and guide you *" +echo -e "* through the complete configuration process. *" +echo -e "* *" +echo -e "* You'll need to provide: *" +echo -e "* • Instance name and domain *" +echo -e "* • Database configuration (local or external) *" +echo -e "* • SMTP server settings for emails *" +echo -e "* • File storage settings (local or S3) *" +echo -e "* *" +echo -e "* 💡 All dependencies (Docker, etc) will be installed for you. *" +echo -e "* *" +echo -e "* ⚠️ For production use, review security settings and documentation. *" +echo -e "* *" +echo -e "***********************************************************************" + +REPOSITORY_PATH=${DECIDIM_PATH:-/opt/decidim} +REPOSITORY_URL="https://github.com/decidim/docker" +REPOSITORY_BRANCH="feat/decidim_install" + +export REPOSITORY_URL +export REPOSITORY_BRANCH + +echo "📁 Installation directory: $REPOSITORY_PATH" + +trap 'echo "❌ Error occurred at line $LINENO. You can re-run this script to restart the installation."' ERR + +if [ ! -d "$REPOSITORY_PATH" ]; then + echo "📁 Creating installation directory: $REPOSITORY_PATH" + if ! sudo mkdir -p "$REPOSITORY_PATH"; then + echo "❌ Failed to create directory $REPOSITORY_PATH" + exit 1 + fi + if ! sudo chown "$USER":"$USER" "$REPOSITORY_PATH"; then + echo "❌ Failed to set ownership of $REPOSITORY_PATH" + exit 1 + fi +fi + +TMP="/tmp/decidim-docker-files" +if [ ! -d "$TMP" ]; then + mkdir "$TMP" +fi + +echo "📥 Downloading the necessary installation files." +curl -fsSL \ + --retry 3 \ + --retry-delay 2 \ + --connect-timeout 30 \ + --max-time 300 \ + --progress-bar \ + -o "$TMP/deploy.zip" \ + "$REPOSITORY_URL/releases/download/latest/deploy.zip" + +echo "📦 Installing unzip package..." +if ! (sudo apt update && sudo apt install unzip -y); then + echo "❌ Failed to install unzip package" + exit 1 +fi + +echo "📂 Extracting files to $REPOSITORY_PATH..." +if ! unzip -u -o "$TMP/deploy.zip" -d "$REPOSITORY_PATH" /dev/null +groupmod -g "$USER_GID" decidim 2>/dev/null +usermod -g "$USER_GID" decidim 2>/dev/null + +chown -R -h "$USER_UID" "$BUNDLE_PATH" +chgrp -R -h "$USER_GID" "$BUNDLE_PATH" + +# Check all the gems are installed or fails. +if ! bundle check; then + echo "❌ Gems in Gemfile are not installed. Installing them with \"bundle install\"..." + bundle install +else + echo "✅ Gems in Gemfile are installed" +fi + +# Check to see if there are migrations to install +bundle exec rake railties:install:migrations + +# Check no migrations are pending migrations +if [ -z "$SKIP_MIGRATIONS" ]; then + bundle exec rails db:migrate + echo "✅ Migrations are all up" +else + echo "⚠️ Skipping migrations!" +fi + +echo "🚀" "$@" +exec "$@" diff --git a/scripts/hello-world.sh b/install/scripts/hello-world.sh similarity index 100% rename from scripts/hello-world.sh rename to install/scripts/hello-world.sh diff --git a/install/scripts/sidekiq_entrypoint.sh b/install/scripts/sidekiq_entrypoint.sh new file mode 100755 index 00000000..4abed28c --- /dev/null +++ b/install/scripts/sidekiq_entrypoint.sh @@ -0,0 +1,15 @@ +#!/bin/sh -x + +# Check all the gems are installed or fails. +if ! bundle check; then + echo "❌ Gems in Gemfile are not installed. Installing them with \"bundle install\"..." + if ! bundle install; then + echo "❌ bundle install failed." + exit 1 + fi +else + echo "✅ Gems in Gemfile are installed" +fi + +echo "🚀" "$@" +exec "$@" diff --git a/install/up.sh b/install/up.sh new file mode 100644 index 00000000..07ff5ee4 --- /dev/null +++ b/install/up.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -e +set -u +set -o pipefail + +ENV_FILE="${REPOSITORY_PATH}/.env" + +# Check if .env file exists +if [ ! -f "$ENV_FILE" ]; then + echo "❌ Error: .env file not found at $ENV_FILE" + echo "Please run the installation script first or create the .env file manually." + exit 1 +fi + +echo "🚀 Starting Decidim containers..." + +docker compose --env-file "$ENV_FILE" up -d + +echo "📋 Displaying recent container logs..." +docker compose logs --tail=30 + +echo "✅ Containers started successfully!" +echo "🔍 You can monitor logs with: docker compose logs -f" diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh deleted file mode 100644 index c48d1f87..00000000 --- a/scripts/entrypoint.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -x - -USER_UID=$(stat -c %u /code/Gemfile) -USER_GID=$(stat -c %g /code/Gemfile) - -export USER_UID -export USER_GID - -usermod -u "$USER_UID" decidim 2> /dev/null -groupmod -g "$USER_GID" decidim 2> /dev/null -usermod -g "$USER_GID" decidim 2> /dev/null - -chown -R -h "$USER_UID" "$BUNDLE_PATH" -chgrp -R -h "$USER_GID" "$BUNDLE_PATH" - -/usr/bin/sudo -EH -u decidim "$@"