I'm on the review process for #119
As we've delayed a lot of months for this review (basically, we wanted to have full focus in v0.32.0 release process), currently on the Association don't have resources for contracting PokeCode for these changes, so the idea is to try to merge the PR as-is, and do the next set of changes on our own.
Blockers
traefik-1 | 2026-07-14T11:13:05Z DBG log/log.go:244 > http: TLS handshake error from 85.85.166.206:33212: remote error: tls: bad certificate
traefik-1 | 2026-07-14T11:13:33Z DBG github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288 > Serving default certificate for request: "decidim-docker.test.decidim.org"
traefik-1 | 2026-07-14T11:13:33Z DBG log/log.go:244 > http: TLS handshake error from 85.85.166.206:35022: remote error: tls: bad certificate
traefik-1 | 2026-07-14T11:13:33Z DBG github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288 > Serving default certificate for request: "decidim-docker.test.decidim.org"
traefik-1 | 2026-07-14T11:13:33Z DBG log/log.go:244 > http: TLS handshake error from 85.85.166.206:35036: remote error: tls: bad certificate
traefik-1 | 2026-07-14T11:13:36Z DBG github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288 > Serving default certificate for request: ""
Error response from daemon: No such container: decidim
Waiting for Rails server to start...
Next tasks
$ docker run -it ubuntu /bin/bash
root@d35055f0806b:/#
root@d35055f0806b:/# zip
bash: zip: command not found
root@d35055f0806b:/# tar
tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' options
Try 'tar --help' or 'tar --usage' for more information.
🔄 Docker installation completed!
📋 Next steps:
1. Log out and log back in, OR run: 'newgrp docker'
2. Re-run this installation script
I'd expect that this be automated too (the newgrp docker and running again)
Related to this, having a manual command that needs to be run also means that it can fail:
root@dev-decidimdocker:/# newgrp docker
bash: newgrp: command not found
(On a clean LXC Ubuntu 26.04 installation)
To run Docker as a non-privileged user, consider setting up the
Docker daemon in rootless mode for your user:
dockerd-rootless-setuptool.sh install
Visit https://docs.docker.com/go/rootless/ to learn about rootless mode.
To run the Docker daemon as a fully privileged service, but granting non-root
users access, refer to https://docs.docker.com/go/daemon-access/
WARNING: Access to the remote API on a privileged Docker daemon is equivalent
to root access on the host. Refer to the 'Docker daemon attack surface'
documentation for details: https://docs.docker.com/go/attack-surface/
This text should be behind a verbose or debug flag, so we don't give confusing technical messages to implementers
If you want, later on you can modify the 'docker-compose.yml' to change the Decidim version.
Current:
/opt/decidim/
├── .env
├── config/
│ ├── schedule.yml
│ └── sidekiq.yml
├── dependencies/
│ ├── build_env.sh
│ ├── check_docker.sh
│ ├── create_system_admin.sh
│ ├── decidim_version.sh
│ ├── generate_gemfile.sh
│ ├── generate_vapid_keys.sh
│ ├── open_ports.sh
│ └── os_version.sh
├── docker-compose.yml
├── Gemfile.local
├── Gemfile.wrapper
├── install.sh
├── jobs/
│ └── invoke_rake_task_job.rb
├── README.md
├── scripts/
│ ├── entrypoint.sh
│ └── sidekiq_entrypoint.sh
└── up.sh
It is difficult to have a good understanding of where do things should belong
Proposed (linuxserver.io style):
/opt/decidim/
├── .env
├── docker-compose.yml
├── Gemfile.local
├── Gemfile.wrapper
├── install.sh
├── up.sh
├── README.md
├── root/
│ ├── defaults/
│ │ ├── schedule.yml
│ │ └── sidekiq.yml
│ └── jobs/
│ └── invoke_rake_task_job.rb
└── scripts/
├── entrypoint.sh
├── sidekiq_entrypoint.sh
└── install/
├── build_env.sh
├── check_docker.sh
├── create_system_admin.sh
├── decidim_version.sh
├── generate_gemfile.sh
├── generate_vapid_keys.sh
├── open_ports.sh
└── os_version.sh
Alternative
/opt/decidim/
├── docker-compose.yml
├── .env # ← only secrets file
├── install.sh
├── README.md
│
├── container/ # Mounted into the container
│ ├── Gemfile.local
│ ├── Gemfile.wrapper
│ ├── entrypoint.sh
│ ├── sidekiq_entrypoint.sh
│ ├── config/
│ │ ├── sidekiq.yml
│ │ └── schedule.yml
│ └── app/jobs/
│ └── invoke_rake_task_job.rb
│
└── setup/ # Host-only scripts
├── up.sh
├── build_env.sh
├── check_docker.sh
├── create_system_admin.sh
├── decidim_version.sh
├── generate_gemfile.sh
├── generate_vapid_keys.sh
├── open_ports.sh
└── os_version.sh
Question:
The dependencies/ directory is actually necessary post-installation? Or it can/should be in /tmp/decidim-docker-files/dependencies/?
- "Image naming has changed recently." and " Biggest naming change" are from 6 years ago
- Leave only decidim hello world example + production one-liner with a link to the official documentation
- Deprecate (with a big warning) the images
decidim-generator, decidim-test, and decidim-dev
- Schedule for full removal at January 2028
A. Recommended: installation script
B. Manual installation
/opt/decidim/bin/rails would be a wrapper for docker compose run -it app bin/rails or similar
What is the name of your organization? (For example: Decidim Barcelona) Decidim Docker Dev
✅ The name of the instance is: Decidim Docker Dev
💡 This is the domain where users will access your Decidim instance.
Make sure you have DNS configured for this domain.
Example: decidim.example.org
domain: decidim-docker.test.decidim.org
✅ Your instance will be accessible at: https://decidim-docker.test.decidim.org
───────────────────────────────────────────────
🗄 Database Configuration
We need to set up your Decidim database.
💡 You can use our built-in PostgreSQL database (recommended for beginners).
or connect to an existing external database.
Do you have an external database already set up? [y/N]
Instead of just domain:, it should be
What is the domain name? (For example: decidim.example.org)
It should also have a ❓ emoji to make it clear every-time we're waiting for a user response
❓ What is the name of your organization? (For example: Decidim Barcelona) Decidim Docker Dev
❓ What is the domain name? (For example: decidim.example.org)
❓ Do you have an external database already set up? [y/N]
Right now:
- Run the curl script
- Ask me to do something manually after 1 minute
- Make me to run the curl script again (that I need to search for the URL as I don't have it in my history, being a new session)
- Stops and ask me to press enter (??) - wait 2 minutes for downloading things
- Ask me some questions
- Download more docker images - wait 2 minutes for downloading things
The flow should be
- Run the curl script
- Ask me all the questions
- Confirm the answers or cancel to start over
- Download everything needed
✅ Containers started successfully!
🔍 You can monitor logs with: docker compose logs -f
It can take up to 5 minutes
I'm on the review process for #119
As we've delayed a lot of months for this review (basically, we wanted to have full focus in v0.32.0 release process), currently on the Association don't have resources for contracting PokeCode for these changes, so the idea is to try to merge the PR as-is, and do the next set of changes on our own.
Blockers
install.shscript #119 (comment)install.shscript #119 (comment)Next tasks
This will generate extra-security on the download of the shell script and the files it uses, giving the final user more security.
I'd expect that this be automated too (the newgrp docker and running again)
Related to this, having a manual command that needs to be run also means that it can fail:
(On a clean LXC Ubuntu 26.04 installation)
This text should be behind a
verboseordebugflag, so we don't give confusing technical messages to implementersBe consistent in the formula used for asking feedback:
for the image, it accepts with enter key
for the ports, it asks for Y/n
Fix typo at
UFW nos intalled. We are going to install it to allow openning ports 80 and 443 on this machine.Integrate a linter for bash in the CI pipeline for this repository (like https://www.shellcheck.net/)
Clean-up the file tree in /opt/decidim
Current:
It is difficult to have a good understanding of where do things should belong
Proposed (linuxserver.io style):
Alternative
Question:
The
dependencies/directory is actually necessary post-installation? Or it can/should be in/tmp/decidim-docker-files/dependencies/?install/install.sh. We have a pending task of migrating to standard SPDX headersdecidim-generator,decidim-test, anddecidim-dev/opt/decidim/bin/railswould be a wrapper fordocker compose run -it app bin/railsor similarInstead of just
domain:, it should beIt should also have a ❓ emoji to make it clear every-time we're waiting for a user response
expectfor checking the correct behaviorRight now:
The flow should be
Other images that aren't
decidim/decidim:latestshould be through an ENV VAR (DECIDIM_DOCKER_IMAGE) - as it is a "power users" kind of featureInstall some minimal security practices: unattended-upgrades and fail2ban (opening a 22 port to the whole Internet should have a bit of security).
When opening a shell inside of the container the user that runs the app is root. This is against the The Principle of Least Privilege
Add a message after
It can take up to 5 minutes
launcherscript with rebuild/start/stop/etc as wrappers for docker compose API. Also with anupdateto download and execute the update process