Guía de Instalación de PSONO Community Edition (CE)

Paso a paso para la instalación de PSONO Community Edition (CE) y no morir en el intento.

Después de varios intentos con la instalación del gestor de contraseñas Psono CE (Community Edition), finalmente logré implementarlo con éxito en un entorno de pruebas, con miras a su posterior despliegue en producción. Durante el proceso me basé en la documentación oficial, aunque encontré algunas limitaciones y omisiones que pueden dificultar la instalación, especialmente para quienes se enfrentan al sistema por primera vez. Por este motivo, he preparado esta guía donde detallo los pasos, consideraciones y ajustes necesarios que descubrí durante la instalación, con el objetivo de facilitar el proceso a otros usuarios que deseen implementar Psono CE y puedan estar enfrentando los mismos inconvenientes.

Para estas pruebas, he considerado usar dos equipos con la versión de sistema operativo Ubuntu Desktop 24.04.2:

  • 1 para la base de datos con 1 CPU, 1.5GB de memoria RAM y 20GB de disco duro.
  • 1 para la aplicación en Docker con 1 CPU, 1GB de memoria RAM y 10GB disco duro.

Importante: Es fundamental tener en cuenta que Psono requiere obligatoriamente dos entornos separados: uno para la base de datos y otro para la aplicación. Esto se debe a que la aplicación debe ejecutarse dentro de un contenedor Docker, y —por alguna razón que he comprobado tras múltiples pruebas— no logra establecer conexión con una base de datos local (localhost). Por lo tanto, si planeas implementar Psono en un solo servidor o equipo, te recomiendo dividir la instalación en dos sistemas distintos:

  • uno que aloje la base de datos, y
  • otro destinado a la aplicación en Docker.

De lo contrario, la instalación no podrá completarse correctamente.


Instalando PostgreSQL para la Base de Datos

Para la implementación de la base de datos, se utilizó PostgreSQL en su versión 13 tal como es indicado en la guía de instalación, pero puede usarse versiones superiores.

1. Se deberá de abrir un Terminal y ejecutar el siguiente comando:

sudo apt -y install vim bash-completion wget gnupg lsb-release
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" | sudo tee  /etc/apt/sources.list.d/pgdg.list
sudo apt -y update
sudo apt -y install postgresql-13 postgresql-client-13

Ejemplo:


2. Luego de ejecutar el comando, debemos de cambiar al usuario de postgres:

sudo -iu postgres

Ejemplo:

3. Crearemos la base de datos llamada "psono":

createdb psono

4. Abriremos el simbolo de sistema de postgres para editar la base de datos "psono":

psql psono

Ejemplo:

5. Ahora crearemos el usuario para la base de datos "psono" y le daremos privilegios al usuario. Para el ejemplo estoy definiendo el usuario "psono" y la contraseña "password" pero deberan de cambiarlo por una contraseña segura creada por ustedes:

CREATE USER psono WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE "psono" to psono;
GRANT CREATE ON SCHEMA public TO psono;

Ejemplo:

6. Instalaremos algunas extensiones necesarias:

CREATE EXTENSION IF NOT EXISTS ltree;
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

Ejemplo:

7. Salimos de la ventana de shell de postgres y volvemos al usuario normal, para ello:

\q (o Ctrl+D)

8. Salimos de postgres completamente y volvemos al usuario de terminal inicial:

exit

9. De forma predeterminada, PostgreSQL no permite conexiones externas, por lo que es necesario realizar una configuración en el archivo "pg_hba.conf". En este archivo se debe añadir la dirección IP del host o equipo que accederá a la base de datos, asociándola al usuario. Esta configuración es clave para que la aplicación Psono la cual se ejecutará en otro servidor (vía Docker) pueda conectarse correctamente a la base de datos.

Ejecutamos el siguiente comando:

sudo vim /etc/postgresql/13/main/pg_hba.conf

Nota: En mi caso uso VIM pero puedes usar NANO u otro editor de texto.

Añadiremos al final de archivo las siguientes lineas en donde deberá de cambiar el valor de <IP> por la IP del equipo donde instalará la aplicación de PSONO CE:

host    psono     psono     127.0.0.1/32      md5
host    psono     psono     ::1/128           md5
host    psono     psono     <IP>/32           md5

Ejemplo:

10. Ahora, modificaremos el archivo "postgresql.conf" para permitir las conexiones remotas, para ello ejecutaremos el siguiente comando:

sudo vim /etc/postgresql/13/main/postgresql.conf

Una vez abierto el archivo, buscaremos la linea "#listen_addresses = 'localhost'", quitaremos el valor comentado (#) y cambiaremos el valor de "localhost" por "*" de la siguiente manera:

Ejemplo:

 

11. Una vez finalizada la configuración, será necesario reiniciar el servicio de base de datos:

sudo systemctl restart postgresql

 

Instalando la Aplicación PSONO CE

Pre-requisitos:

Antes de la instalación de PSONO, es necesario que el servidor tenga la aplicación de docker instalda, si no la tiene, necesitaremos realizar lo siguiente:

1. Ejecutar el siguiente comando para desinstalar paquetes que puedan generar conflictos con Docker:

for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done

2. Estableciendo el repositorio de Docker con apt:

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

3. Instalando los paquetes de Docker, para ello ejecutaremos el siguiente comando:

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

4. (Opcional) Si deseas validar que la instalación se ejecutó correctamente puedes ejecutar el siguiente comando:

sudo docker run hello-world

 

Instalación:

1. Ya con la aplicación de Docker instalada, como primer paso sera la generación de las llaves, para ello ejecutaremos el siguiente comando:

sudo docker run --rm -ti psono/psono-combo:latest python3 ./psono/manage.py generateserverkeys

2. Una vez ejecutado el comando, deberemos de tomar nota de los valores generados para SECRET_KEY, ACTIVATION_LINK_SECRET, DB_SECRET, EMAIL_SECRET_SALT, PRIVATE_KEY y PUBLIC_KEY, estos valores seran necesarios para configurar la aplicación.

3. Necesitaremos crear una carpeta donde estará la aplicación y luego necesitaremos crear un archivo dentro de dicha carpeta donde estará el archivo de configuración "settings.yaml", para este caso definiremos la carpeta "/opt/docker/psono":

sudo mkdir /opt/docker
sudo mkdir /opt/docker/psono
sudo vim /opt/docker/psono/settings.yaml

4. En el archivo creado, pegaremos el siguiente contenido reemplazando los valores generdos en el punto 2:

# Replace the keys below with the one from the generateserverkeys command.
SECRET_KEY: 'SOME SUPER SECRET KEY THAT SHOULD BE RANDOM AND 32 OR MORE DIGITS LONG'
ACTIVATION_LINK_SECRET: 'SOME SUPER SECRET ACTIVATION LINK SECRET THAT SHOULD BE RANDOM AND 32 OR MORE DIGITS LONG'
DB_SECRET: 'SOME SUPER SECRET DB SECRET THAT SHOULD BE RANDOM AND 32 OR MORE DIGITS LONG'
EMAIL_SECRET_SALT: '$2b$12$XUG.sKxC2jmkUvWQjg53.e'
PRIVATE_KEY: '02...0b'
PUBLIC_KEY: '02...0b'

# The URL of the web client (path to e.g activate.html without the trailing slash)
WEB_CLIENT_URL: 'https://psono.example.com'

# The number of proxies in your environment to parse the X-Forwarded-For header. The basic setup of Psono uses 2
# reverse proxies, the regular one and one in the combo container. If you have additional Loadbalancers you may have
# adjust this parameter.
NUM_PROXIES: 2

# The URL of the favicon service. You can
# a) host an own favicon server
# b) use a privacy friendly https://favicon.psono.com/v1/icon/
# c) use any other provider, e.g. google's https://t3.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&size=128&url=http://
# WARNING: The "first url filter" (e.g. domain or IP) configured for an entry will be sent to the service.
#
FAVICON_SERVICE_URL: 'https://favicon.psono.com/v1/icon/'

# Switch DEBUG to false if you go into production
DEBUG: False

# Adjust this according to Django Documentation https://docs.djangoproject.com/en/2.2/ref/settings/
ALLOWED_HOSTS: ['*']

# Should be your domain without "www.". Will be the last part of the username
ALLOWED_DOMAINS: ['example.com']

# If you want to disable registration, you can comment in the following line
# ALLOW_REGISTRATION: False

# If you want to disable the lost password functionality, you can comment in the following line
# ALLOW_LOST_PASSWORD: False

# If you want to enforce that the email address and username needs to match upon registration
# ENFORCE_MATCHING_USERNAME_AND_EMAIL: False

# If you want to restrict registration to some email addresses you can specify here a list of domains to filter
# REGISTRATION_EMAIL_FILTER: ['company1.com', 'company2.com']

# Should be the URL of the host under which the host is reachable
# If you open the url and append /info/ to it you should have a text similar to {"info":"{\"version\": \"....}
HOST_URL: 'https://psono.example.com/server'

# The email used to send emails, e.g. for activation
# ATTENTION: If executed in a docker container, then "localhost" will resolve to the docker container, so
# "localhost" will not work as host. Use the public IP or DNS record of the server.
EMAIL_FROM: 'the-mail-for-for-example-useraccount-activations@test.com'
EMAIL_HOST: 'smtp.example.com'
EMAIL_HOST_USER: ''
EMAIL_HOST_PASSWORD : ''
EMAIL_PORT: 25
EMAIL_SUBJECT_PREFIX: ''
EMAIL_USE_TLS: False
EMAIL_USE_SSL: False
EMAIL_SSL_CERTFILE:
EMAIL_SSL_KEYFILE:
EMAIL_TIMEOUT: 10

# If you have your own Yubico servers, you can specify here the urls as a list
# YUBICO_API_URLS: ['https://api.yubico.com/wsapi/2.0/verify']

# Cache enabled without belows Redis may lead to unexpected behaviour

# Cache with Redis
# By default you should use something different than database 0 or 1, e.g. 13 (default max is 16, can be configured in
# redis.conf) possible URLS are:
#    redis://[:password]@localhost:6379/0
#    rediss://[:password]@localhost:6379/0
#    unix://[:password]@/path/to/socket.sock?db=0
# CACHE_ENABLE: False
# CACHE_REDIS: False
# CACHE_REDIS_LOCATION: 'redis://127.0.0.1:6379/13'

# Enables the management API, required for the psono-admin-client / admin portal (Default is set to False)
MANAGEMENT_ENABLED: True

# Enables the fileserver API, required for the psono-fileserver
# FILESERVER_HANDLER_ENABLED: False

# Enables files for the client
# FILES_ENABLED: False

# Allows that users can search for partial usernames
# ALLOW_USER_SEARCH_BY_USERNAME_PARTIAL: True

# Allows that users can search for email addresses too
# ALLOW_USER_SEARCH_BY_EMAIL: True

# Disables central security reports
# DISABLE_CENTRAL_SECURITY_REPORTS: True

# Configures a system wide DUO connection for all clients
# DUO_INTEGRATION_KEY: ''
# DUO_SECRET_KEY: ''
# DUO_API_HOSTNAME: ''

# If you are using the DUO proxy, you can configure here the necessary HTTP proxy
# DUO_PROXY_HOST: 'the-ip-or-dns-name-goes-here'
# DUO_PROXY_PORT: 80
# DUO_PROXY_TYPE: 'CONNECT'
# If your proxy requires specific headers you can also configure these here
# DUO_PROXY_HEADERS: ''

# Normally only one of the configured second factors needs to be solved. Setting this to True forces the client to solve all
# MULTIFACTOR_ENABLED: True

# Allows admins to limit the offered second factors in the client
# ALLOWED_SECOND_FACTORS: ['yubikey_otp', 'google_authenticator', 'duo', 'webauthn', 'ivalt']

# In case one wants to use iVALT, please add ivalt_secret_key. If you don't have then please write to ivat at 'support@ivalt.com'.
# IVALT_SECRET_KEY: ''

# Your Postgres Database credentials
# ATTENTION: If executed in a docker container, then "localhost" will resolve to the docker container, so
# "localhost" will not work as host. Use the public IP or DNS record of the server.
DATABASES:
    default:
        'ENGINE': 'django.db.backends.postgresql_psycopg2'
        'NAME': 'psono'
        'USER': 'psono'
        'PASSWORD': 'password'
        'HOST': 'localhost'
        'PORT': '5432'
# for master / slave replication setup comment in the following (all reads will be redirected to the slave
#    slave:
#        'ENGINE': 'django.db.backends.postgresql_psycopg2'
#        'NAME': 'YourPostgresDatabase'
#        'USER': 'YourPostgresUser'
#        'PASSWORD': 'YourPostgresPassword'
#        'HOST': 'YourPostgresHost'
#        'PORT': 'YourPostgresPort'

# The path to the template folder can be "shadowed" if required later
TEMPLATES: [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['/root/psono/templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Luego deberemos de modifcar el contenido del archivo de configuración considerando lo siguiente:

a. Debemos de reemplazar las primera 6 lineas con las llaves generadas en el punto 2.
b. WEB_CLIENT_URL: Indica la URL que se usará el cliente web.
c. HOST_URL: Para indicar la URL que se usará para acceder a la aplicación mediante el cliente web. Es importante mantener el sufijo "/server" al final de la URL.
d. ALLOWES_DOMAINS: Para establecer tu dominio. Debemos de indicar si la URL. Puede ser un dominio interno o el dominio público externo en caso de que la aplicación sea accesible desde Internet.
e. Los parametros de Email pueden configurarse tanto en el archivo de configuración como dentro de la aplicación y dependerá del servicio de Email que tengas contratado o implementado de manera local.
f. Para la Base de Datos, debemos de colocar los valores configurados en la primera parte de la guia indicando el nombre de la base de datos, usuario, contraseña, IP del servidor y el puerto.

Ejemplo:
A continuación les comparto un ejemplo del archivo de configuración del ambiente de pruebas que implementé:

En mi caso y como lo estoy implementando en un entorno local para las pruebas, estoy usando el nombre de dominio "srvpsonoce.local" que luego y para una mayor comodidad de acceso se puede modifcar el archivo host de la estación de la red local para acceder o si se encuentra en dominio, se podria crear un registro en el DNS del AD y asociarlo a la IP.

4. (Opcional) ara verificar que los parámetros de correo configurados sean correctos, es posible ejecutar el siguiente comando de prueba de envío hacia una dirección de correo, por ejemplo: something@something.com. Este paso permite confirmar que el servidor de correo y las credenciales configuradas funcionan adecuadamente antes de integrarlo con Psono.

sudo docker run --rm \
  -v /opt/docker/psono/settings.yaml:/root/.psono_server/settings.yaml \
  -ti psono/psono-combo:latest python3 ./psono/manage.py sendtestmail something@something.com

Ejemplo:

5. Preparando la base de datos, para ello debemos de ejecutar el siguiente comando:

sudo docker run --rm \
  -v /opt/docker/psono/settings.yaml:/root/.psono_server/settings.yaml \
  -ti psono/psono-combo:latest python3 ./psono/manage.py migrate

Ejemplo: 

6. Debemos de crear una carpeta que contendrá el archivo de configuración del cliente, para ello ejecutaremos el siguiente comando, considerando que estoy definiendo que la ruta donde estará el archivo de configuración será "/opt/docker/psono-client/":

sudo mkdir /opt/docker/psono-client/
sudo vim /opt/docker/psono-client/config.json

7. Ahora, debemos de pegar las siguientes lineas en el nuevo archivo creado:

{
  "backend_servers": [{
    "title": "Psono.pw",
    "url": "https://psono.example.com/server"
  }],
  "base_url": "https://psono.example.com/",
  "allow_custom_server": true,
  "allow_registration": true,
  "allow_lost_password": true,
  "disable_download_bar": false,
  "authentication_methods": ["AUTHKEY", "LDAP"],
  "saml_provider": []
}

Luego deberemos de modifcar el contenido del archivo de configuración considerando lo siguiente:

a. title: el texto que se mostrará al acceder al sitio web de Psono.
b. url: la misma que HOST_URL que configuramos en settings.yaml.
c. base_url: la misma que url, pero sin el /server.

Ejemplo: 
A continuación les comparto un ejemplo del archivo de configuración del ambiente de pruebas que implementé:

8. Seguidamente, debemos de ejecutar el siguiente comando para que la aplicación de Psono CE inicie en el contenedor de Docker:

sudo docker run --name psono-combo \
    --sysctl net.core.somaxconn=65535 \
    -v /opt/docker/psono/settings.yaml:/root/.psono_server/settings.yaml \
    -v /opt/docker/psono-client/config.json:/usr/share/nginx/html/config.json \
    -v /opt/docker/psono-client/config.json:/usr/share/nginx/html/portal/config.json
    -d --restart=unless-stopped -p 10200:80 psono/psono-combo:latest

Ejemplo:

Esto iniciará el servidor Psono en el puerto 10200. Si abres ahora http://<IP>:10200/server/info/ deberías ver algo como esto:

9. Por último, debemos de crear la tarea de mantenimiento, para ello será necesario configurarlo con un cron ejecutando los siguientes comandos:

crontab -e

Y luego colocaremos la siguiente linea:

30 2 * * * /usr/bin/docker run --rm -v /opt/docker/psono/settings.yaml:/root/.psono_server/settings.yaml psono/psono-combo:latest python3 ./psono/manage.py cleartoken >> /var/log/cron.log 2>&1

10. Si todo lo hemos ejecutado correctamente, deberia de cargarnos la aplicación desde un navegador de la siguiente manera:

 

Creando el Primer Usuario Administrador

Luego de configurar Psono CE, puede crear su primer usuario. Si configuró el correo, se puede usar el procedimiento de registro habitual el cual consiste en registrarse desde la web haciendo clic en el boton de "Register". De lo contrario, puede usar el siguiente comando para crear un usuario desde la línea de comandos:

1. Para crear el usuario desde linea de comando se deberá de ejecutar lo siguiente:

sudo docker run --rm \
  -v /opt/docker/psono/settings.yaml:/root/.psono_server/settings.yaml \
  -ti psono/psono-combo:latest python3 ./psono/manage.py createuser username@example.com myPassword email@something.com

Ejemplo:

2. Ahora, con el usuario creado, podremos otorgarle permisos de Administración, para ello debemos de ejecutar el siguiente comando:

sudo docker run --rm \
  -v /opt/docker/psono/settings.yaml:/root/.psono_server/settings.yaml \
  -ti psono/psono-combo:latest python3 ./psono/manage.py promoteuser username@example.com superuser

Ejemplo:

3. Con la cuenta de usuario creada podremos probar ingresando al portal de Psono CE.

Referencias:
https://doc.psono.com/admin/installation/install-preparation.html#system-requirements
https://doc.psono.com/admin/installation/install-postgres-db.html#preamble
https://doc.psono.com/admin/installation/install-psono-ce.html#installation
https://doc.psono.com/admin/installation/install-finalize.html#preamble
https://docs.docker.com/engine/install/ubuntu/