Skip to main content

Self hosted TiBillet instances

danger

Since January 1, 2018, in order to combat VAT fraud, all VAT-registered professionals recording customer payments using one of these software or systems are required to use secure, certified hardware.

A measure enshrined in Article 286 3° bis of the General Tax Code and initially stemming from the 2016 Finance Act, when April became involved in promoting and defending open-source software with cashiering functions.

If you're using TiBillet's Coop' and SaaS model, you don't need to worry about any of this : We provide you with the certificate.

But if you self-host your own cash register instance, you legally become the publisher, and we can't provide you with any legal documents to present to the tax authorities.

I imagine that if you're here, it's to install it yourself ;)

Here you are informed!

More information here (in french) :

Introduction to Engines

Tibillet is a software suite composed of several interoperable building blocks. The engines are :

  • Fedow: Federated and open wallet, the federation engine. A PoA and Rsa key based blockchain to share membership assets, local currencies and time for several Lespass and LaBoutik instances.

  • Lespass: Ticketing, booking, membership and landing page engines. Usefull too for refill online with self scanned qrcode unique on each card.

  • LaBoutik: Cash register, cashless system with RFID / NFC chip and order-taking system.

To get the full functionality of TiBillet, you need to install these three engines.

  • One Fedow for multiple locations (RSA based PoA blockchain)
  • One Lespass for multiple locations (Django multi-tenant)
  • One Laboutik per location, which connects to a fedow and a lespass to join a federation.
Exemple

if you want to use the same NFC card to manage cashless at 2 festivals and 3 community cafés, you'll need 5 LabouTik, but only one Fedow for the federated asset, and one Lespass for the webpage of each venue. The same applies if you want to manage a co-working subscription for a group of third place in a given city/region/department.

Requirements :

For security and performance reasons, we recommend that you separate the Lespass public area from the LaBoutik checkout and Fedow federation engines.

For dev' and test purpose, you can install everything on one VPS. Here the minimal requirements :

A linux server with :

  • 2 vCpu / 4Go Ram
  • Docker & Compose
  • 1 domain with wildcard capacity
  • A Reverse proxy who handle 443 and 80 port (we use Traefik)
  • A valid Stripe account with Stripe connect

You can find some ressource (in french) here :

If you're ready for adventure, create a new folder "TiBillet", and let's start by installing a Fedow!

mkdir TiBillet && cd TiBillet

Generate many Fernet key and django secret key

You will need 3 couple of Fernet/Django secret key.

# Generate fernet key with the fedow image :
# Choose one line and fill the .env file
docker run --rm tibillet/fedow:alpha1.2 poetry run python3 -c "from cryptography.fernet import Fernet; print('\n'.join([Fernet.generate_key().decode('utf-8') for i in range(0,30)]))"

# Generate django secret key with the fedow image :
# Choose one line and fill the .env file
docker run --rm tibillet/fedow:alpha1.2 poetry run python3 -c "from django.core.management.utils import get_random_secret_key; print('\n'.join([get_random_secret_key() for i in range(0,30)]))"

Fedow : One ring to rule them all

mkdir TiBillet/Fedow && cd TiBillet/Fedow

Create .env file and fill it with your own variable

# Create .env and fill with :
SECRET_KEY='' # see upper to create one
FERNET_KEY='' # see upper to create one
DOMAIN='' # ex : fedow.domain.com
STRIPE_KEY='' # from your stripe account

Prepare the rocket launch

# Create frontend and backend network with docker
docker network create frontend
docker network create fedow_backend

# prepare the logs, assets, database and nginx conf folder
mkdir logs www database nginx

Nginx rules

Créate the file with nano nginx/django.conf

server {
listen 80;
server_name localhost;

access_log /logs/nginxAccess.log;
error_log /logs/nginxError.log;

location /static {
root /www;
}

location /media {
root /www;
}

location / {
# everything is passed to Gunicorn
proxy_pass http://fedow_django:8000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_redirect off;
}
}

The docker-compose.yml file

services:
fedow_memcached:
image: memcached:1.6
container_name: fedow_memcached
hostname: fedow_memcached
restart: always
networks:
- fedow_backend

fedow_django:
image: tibillet/fedow:latest
container_name: fedow_django
hostname: fedow_django
restart: always
env_file: .env
user: fedow
volumes:
- ./database:/home/fedow/Fedow/database
- ./www:/home/fedow/Fedow/www
- ./logs:/home/fedow/Fedow/logs
links:
- fedow_memcached:memcached
networks:
- fedow_backend

fedow_nginx:
image: nginx:latest
restart: always
container_name: fedow_nginx
hostname: fedow_nginx
volumes:
- ./www:/www
- ./logs:/logs
- ./nginx:/etc/nginx/conf.d
depends_on:
- fedow_django
links:
- fedow_django:fedow_django
labels:
- traefik.enable=true
- traefik.docker.network=frontend
- traefik.http.routers.fedow_nginx.tls.certresolver=myresolver
- traefik.http.routers.fedow_nginx.rule=Host(`$DOMAIN`)
- traefik.http.services.fedow_nginx.loadbalancer.server.port=80
networks:
- frontend
- fedow_backend


networks:
frontend:
external: true
fedow_backend:

Launch the rocket !

docker compose up -d 
# To see the logs :
docker compose logs -f

And check to https://<FEDOW_DOMAIN>/dashboard

Congratulation, You own your blockchain ;)

Backup

To make a backup, simply back up the database folder regularly.

Lespass : Multi tenant engine for membership, ticketing and online cashless refill.

Lespass is a multi-tenant engine. It is designed to work with a traefik and a wildcard certificate. See the Code Commun blog for exemple : https://codecommun.coop/blog/sysadmin-mon-chaton-part2

For a test and development environment, it can be run on the same environment as Fedow :

mkdir TiBillet/Lespass && cd TiBillet/Lespass

Prepare the rocket launch

# prepare the logs, assets, backup and database folder
mkdir logs www backup database nginx

Create .env file and fill it with your own variable

# Secret
DJANGO_SECRET='' # see upper to create one
FERNET_KEY='' # see upper to create one

STRIPE_KEY='' # from your stripe account
# or
STRIPE_KEY_TEST=''
STRIPE_TEST=0 # set to 1 for use stripe test env

# Database
POSTGRES_HOST='lespass_postgres'
POSTGRES_USER='lespass_postgres_user'
POSTGRES_PASSWORD='' # strong ! generate a new fernet for exemple.
POSTGRES_DB='lespass'

TIME_ZONE='Europe/Paris' # or where you are
PUBLIC='TiBillet Coop.' # The name of the root instance

FEDOW_DOMAIN='' # the same as Fedow

DOMAIN='' # for the wildcard : without subdomain ! ex : tibillet.coop, not lespass.tibillet.coop
SUB='' # the sub domain of your first place ex : if 'festival', it will be accessible on https://festival.tibillet.coop
META='' # the federated agenda for all events on all tenants. If 'agenda', it will be accessible, for exemple, on https://agenda.tibillet.coop

# For transactionnal email :
EMAIL_HOST=''
EMAIL_PORT=''
EMAIL_HOST_USER=''
EMAIL_HOST_PASSWORD=''

# Change only if needed :
CELERY_BROKER='redis://redis:6379/0'
CELERY_BACKEND='redis://redis:6379/0'

Nginx rules

Créate the file with nano nginx/lespass.conf

server {

listen 80;
server_name localhost;

access_log /logs/nginxAccess.log;
error_log /logs/nginxError.log;

location /static {
root /www;
}

location /media {
root /www;
}

location / {
# everything is passed to Gunicorn
proxy_pass http://lespass_django:8002;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
proxy_http_version 1.1;
client_max_body_size 4M;
proxy_buffer_size 16k;
proxy_buffers 32 16k;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $server_name;
}
}

The docker-compose.yml file

services:
lespass_postgres:
image: postgres:13-bookworm
restart: unless-stopped
container_name: lespass_postgres
hostname: lespass_postgres
volumes:
- ./database/data:/var/lib/postgresql/data
env_file: .env
networks:
- lespass_backend

lespas_memcached:
image : memcached:1.6
container_name: lespas_memcached
hostname: lespas_memcached
restart: always
networks:
- lespass_backend

lespas_redis:
container_name: lespas_redis
hostname: lespas_redis
image: redis:7.2.3-bookworm
restart: unless-stopped
networks:
- lespass_backend

lespass_django:
image: tibillet/lespass:latest
restart: unless-stopped
container_name: lespass_django
hostname: lespass_django
volumes:
- ./www:/DjangoFiles/www
- ./logs:/DjangoFiles/logs
- ./backup:/Backup
env_file: .env
depends_on:
- lespass_postgres
- lespas_redis
links:
- lespass_postgres:postgres
- lespas_redis:redis
- lespas_memcached:memcached
networks:
- lespass_backend
# command: "sleep infinity"

lespass_celery:
image: tibillet/lespass:latest
container_name: lespass_celery
hostname: lespass_celery
env_file: .env
depends_on:
- lespass_postgres
- lespas_redis
links:
- lespass_postgres:postgres
- lespas_redis:redis
- lespas_memcached:memcached
networks:
- lespass_backend
# command: "sleep infinity"
command: "poetry run celery -A TiBillet worker -l INFO"


lespass_nginx:
image: nginx:latest
container_name: lespass_nginx
hostname: lespass_nginx
links:
- lespass_django:lespass_django
volumes:
- ./www:/www
- ./logs:/logs
- ./nginx:/etc/nginx/conf.d
labels:
- traefik.enable=true
- traefik.docker.network=frontend
- traefik.http.routers.lespass_nginx.tls.certresolver=myresolver
- traefik.http.routers.lespass_nginx.rule=Host(`$DOMAIN`) || Host(`www.$DOMAIN`) || Host(`$META.$DOMAIN`) || Host(`$SUB.$DOMAIN`)
- traefik.http.services.lespass_nginx.loadbalancer.server.port=80
networks:
- frontend
- lespass_backend



networks:
frontend:
external: true
lespass_backend: