Simplicité with Portainer & Traefik
Portainer is a professional Docker cluster management tool that facilitates installation and operation of Docker containers. This lesson leverages its power to rapidly install Simplicité instances on a server, with the following objectives:
- minimal manual configuration
- SSL certificates auto-setup with Let's Encrypt
- HTTP -> HTTPS redirection
- Traefik's reverse proxy dashboard activated and available at
traefik.my.domain
behindadmin / _ChangeItNow_
default basic auth (can be changed usinghtpasswd -bn your_user_name your_super_complex_password | sed 's/\$/$$/g'
, doubling the$
is required) - Portainer available at
portainer.my.domain
- allow remote debugging
1) Server deployment
Sizing of the server should be made according to the needs, as always. Any up-to-date unix image should be able to run the containers.
Click to open
- Medium-sized server :
- 2 vCores
- 50GiB storage
- 250Mbps bandwidth
- Almalinux 9 image
2) System configuration
Firewall
Installing a local firewall is highly recommended, for instance by issuing the following commands:
sudo dnf -y install firewalld && sudo dnf clean all
sudo systemctl enable firewalld
sudo systemctl start firewalld
Configuration: here it allows HTTP(S) and SSH traffic from any source:
sudo firewall-cmd --add-service=ssh --permanent
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --remove-service=cockpit --permanent
sudo firewall-cmd --reload
Verify the configuration:
sudo firewall-cmd --list-all
System time
Adjust the system date and timezone to your nee, e.g.
sudo timedatectl set-timezone Europe/Paris
SSH connection method
It is highly recommended to allow only SSH connections using SSH keys (remember to disable password authentication after having configured the allowed SSH keys)
System updates
The system must be up-to-date before proceeding:
sudo dnf update -y
The system must be kept up-to-date by either executing the above command regularly, or by setting up automatic updates. If you activate automatic reboot, make sur you have some kind of VM backup setup.
sudo dnf install dnf-automatic -y
sudo sed -i 's/^reboot=.*/reboot=when-needed/' /etc/dnf/automatic.conf
sudo systemctl edit --full dnf-automatic.timer
sudo systemctl enable --now dnf-automatic.timer
2) Docker Install
Portainer needs Docker as a requirement, so it will be installed after usual upgrades. Based on docker CentOS install docs (adapted)
sudo dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl start docker
sudo systemctl enable docker
sudo docker run hello-world # check everything is running smoothly
Portainer also needs SELinux to be disabled:
sudo sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
sudo reboot
Optionally a firewall should be configured on the host (or among the host) to allow only the relevant traffic.
Minimal configuration is to allow the HTTP port 80
and HTTPS port 443
(along with the SSH port 22
from legitimate origins) through this firewall.
3) Portainer install with lets encrypt and traefik
This is an adaptation of Portainer's doc "Deploying Portainer behind Traefik Proxy"
- create a local
acme.json
with600
rights prior to starting this Docker compose configuration - copy, adapt, and paste the following configuration at the home of your user
- start the configured services with
sudo docker compose up -d
- verify that you have access to
traefik.my.domain
andportainer.my.domain
Do not use the following configuration as is, make sure to adapt all lines that are marked ADAPT
in the configuration.
To generate the basic auth user / pwd, you can use the following command line (doubling the $
is required)
htpasswd -bn your_user_name your_super_complex_password | sed 's/\$/$$/g'
See config
services:
traefik:
container_name: traefik
image: "traefik:latest"
ports:
- "80:80"
- "443:443"
networks:
- proxy
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./acme.json:/acme.json"
command:
- --api.insecure=true
- --api.dashboard=true # ADAPT to deactivate Traefik dashboard
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entryPoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.websecure.address=:443
- --entrypoints.websecure.asdefault=true
- --log.level=INFO
- --accesslog=true
- --providers.docker
- --providers.docker.network=proxy
- --providers.docker.exposedByDefault=false
- --certificatesresolvers.leresolver.acme.httpchallenge=true
- --certificatesresolvers.leresolver.acme.email=mail@my.domain # ADAPT email for the generation of SSL certificates with Let's Encrypt.
- --certificatesresolvers.leresolver.acme.storage=./acme.json
- --certificatesresolvers.leresolver.acme.httpchallenge.entrypoint=web
labels:
- traefik.enable=true
- traefik.http.routers.mydashboard.rule=Host(`traefik.my.domain`) # ADAPT domain name
- traefik.http.routers.mydashboard.tls.certresolver=leresolver
- traefik.http.routers.mydashboard.entrypoints=websecure
- traefik.http.routers.mydashboard.service=api@internal
- traefik.http.routers.mydashboard.middlewares=myauth
- traefik.http.middlewares.myauth.basicauth.users=admin:$$apr1$$HQ4CZZxC$$kUrQ6qAFrX4v/EAYFdrsh1 # ADAPT basic auth
portainer:
image: portainer/portainer-ce:latest
command: -H unix:///var/run/docker.sock
restart: always
networks:
- proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
labels:
# Frontend
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`portainer.my.domain`)" # ADAPT domain name
- "traefik.http.routers.frontend.entrypoints=websecure"
- "traefik.http.services.frontend.loadbalancer.server.port=9000"
- "traefik.http.routers.frontend.service=frontend"
- "traefik.http.routers.frontend.tls.certresolver=leresolver"
# Edge
- "traefik.http.routers.edge.rule=Host(`edge.my.domain`)" # ADAPT domain name
- "traefik.http.routers.edge.entrypoints=websecure"
- "traefik.http.services.edge.loadbalancer.server.port=8000"
- "traefik.http.routers.edge.service=edge"
- "traefik.http.routers.edge.tls.certresolver=leresolver"
networks:
proxy:
name: proxy
volumes:
portainer_data:
The Traefik container and the Simplicité instances have to run in the same Docker network, that's why a "proxy" network is created where all containers will be placed.
4) Configure
- access
https://portainer.my.domain
right after starting the service (it's only configurable for a limited amount of time) - create local environment
- create registry.simplicite.io registry, with authentication
- pull a Simplicité image
5) Start a Simplicité instance
This is the minimal configuration to get a working Simplicité (non persistent) instance. Create a "stack" (a docker compose deployment, in Portainer's semantics), and paste the following config.
services:
test:
image: registry.simplicite.io/platform:6-latest-light
restart: unless-stopped
container_name: test
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.test.rule=Host(`test.my.domain`)"
- "traefik.http.routers.test.entrypoints=websecure"
- "traefik.http.routers.test.tls.certresolver=leresolver"
- "traefik.http.services.test.loadbalancer.server.port=8443"
networks:
proxy:
name: proxy
To make it persistent add the following volumes to the above configuration:
services:
test:
(...)
volumes:
- db:/usr/local/tomcat/webapps/ROOT/WEB-INF/db
- dbdoc:/usr/local/tomcat/webapps/ROOT/WEB-INF/dbdoc
- git:/usr/local/tomcat/webapps/ROOT/WEB-INF/git
(...)
volumes:
db:
dbdoc:
git:
To enable JPDA remote debugging add the following environment variables and open an access to port 8000
. Assign a different port to each instance (8001, 8002, 8003...).
services:
test:
(...)
ports:
- 8001:8000 # expose port 8000
environment:
(...)
JPDA: "true"
JPDA_SUSPEND: "<y|n, defaults to n>" # true to wait for debugger
(...)
To use developer mode for development-oriented features and for the Simplicité VSCode tools extension, add the following DEV_MODE
environment variable.
services:
test:
(...)
environment:
(...)
DEV_MODE: true
(...)
6) Configure stack templates
You can also configure Portainer to use our stack templates, to do so change the App Templates URL in the settings using this URL: https://cdn.jsdelivr.net/gh/simplicitesoftware/resources@latest/public/portainer_templates/templates.json
Or manually configure custom templates using the *.yml
present at this location.
Backup an instance
This script makes the assumption that you have deployed with portainer a stack that with an app service (Simplicité) and a database service (PostgreSQL). You can call it daily and setup rotating backups.
Click to see backup script example
# stop stack
BACKUPDIR=$(date +"backup-%Y-%m-%d-%H%M")
COMPOSE_PROJECT="XXXX" # the name of the stack
APP_SERVICE="XXXX" # name of the service (not the container)
APP_DBDOC_VOLUME="XXXX" # name of the volume (careful, docker compose prefixes it with the stack name)
PSQL_SERVICE=""
PSQL_DBNAME="simplicite"
PSQL_DBUSER="simplicite"
mkdir $BACKUPDIR
# stop Simplicité service
sudo docker compose -p $COMPOSE_PROJECT stop $APP_SERVICE
# save database dump
sudo docker compose -p $COMPOSE_PROJECT exec $PSQL_SERVICE sh -c "rm -f /var/lib/backup/database.dump"
sudo docker compose -p $COMPOSE_PROJECT exec $PSQL_SERVICE sh -c "pg_dump -U $PSQL_DBUSER $PSQL_DBNAME > /var/lib/backup/database.dump"
sudo docker compose -p $COMPOSE_PROJECT cp $PSQL_SERVICE:/var/lib/backup/database.dump $BACKUPDIR/database.dump
# save dbdoc
sudo docker run -v $APP_DBDOC_VOLUME:/data --name helper busybox true
sudo docker cp helper:/data $BACKUPDIR/dbdoc
sudo docker rm helper
# restart Simplicité service
sudo docker compose -p $COMPOSE_PROJECT start $APP_SERVICE
# create archive & clean
tar -czvf $BACKUPDIR.tgz $BACKUPDIR
rm -rf $BACKUPDIR