Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bienvenido


Mis notas

Tux

Codeberg (Git + SSH)


Autenticación SSH

git config --global user.name "John Doe"
git config --global user.email "johnDoe123@email.com"
ssh-keygen -t ed25519 -a 100
# Presiona Enter para usar el valor por defecto
# Define una contraseña

cat ~/.ssh/id_ed25519.pub

Copia el ssh-ed… hasta el final, sin el user@algo.

Agrega esto en Codeberg -> config -> add ssh.

Configurar usuario para commits

Haz lo que indica el mensaje, pero usa el correo con @noreply que aparece en los ajustes del perfil (al final de la página).

Git


Básico

git clone <repositorio>
git status # Mostrará si hay cambios
git add <Archivos/Directorios>
git commit -m "Mensaje de commit"
git push # Envía los cambios al remoto configurado
git reset --soft HEAD~1 # Eliminar último commit

Varios

# 1. Crear y cambiar a una rama nueva  
git checkout -b [nombre-rama]  
# Ej: git checkout -b feature/login → Crea la rama "feature/login" y se mueve a ella.*

# 2. Cambiar a una rama existente  
git checkout [nombre-rama]  
# Ej: git checkout main → Te mueve a la rama main.*

# 3. Subir una rama nueva al repositorio remoto (solo la primera vez)
git push -u origin [nombre-rama]  
# El -u vincula la rama local con la remota para futuros push.*

# 4. Listar ramas locales y remotas  
git branch -a  
# Muestra todas las ramas (locales en verde, remotas en rojo).*

# 5. Sincronizar rama actual con cambios remotos  
git pull  
# Descarga cambios del repositorio remoto y los fusiona con tu rama local.*

# 6. Fusionar una rama con la rama actual  
git merge [nombre-rama]  
# Ej: Si estás en main → git merge feature/login une feature/login con main.*

# 7. Eliminar rama local  
git branch -d [nombre-rama]  
# -d solo borra si está fusionada; usa -D para forzar eliminación.*

# 8. Eliminar rama remota  
git push origin --delete [nombre-rama]  
# Ej: git push origin --delete feature/login → Borra la rama en GitHub.*

# 9. Ver estado actual (cambios, rama, conflictos)  
git status  

# 10. Ver historial de commits  
git log --oneline  
# Muestra commits resumidos en una línea.*

# 11. Tag
git tag name-tag
git push origin name-tag

# 12. Worktree
git worktree add <ruta/del/nuevo/directorio> <rama>
# Crea otro directorio para manejar dos ramas

mdBook


Crates.io

Instalación

cargo install mdbook

Resumen rápido

  Crear libros online escribiendo archivos Markdown.
  Más información: <https://rust-lang.github.io/mdBook/>.

  Crear un proyecto mdBook en el directorio actual:

      mdbook init

  Crear un proyecto mdBook en un directorio específico:

      mdbook init ruta/al/directorio

  Limpiar el directorio con el libro generado:

      mdbook clean

  Servir un libro en <http://localhost:3000>, con auto build al cambiar archivos:

      mdbook serve

  Observar archivos y construir automáticamente cuando cambien:

      mdbook watch

Pages


En Codeberg con mdBook.

git checkout --orphan pages
git rm -rf .  # Borra todos los archivos del tracking
git commit --allow-empty -m "Initial commit for pages branch"
git push origin pages
git checkout main # Vuelve a tu rama principal

git worktree add ../repo-pages pages

Modificar los scripts deploy.sh y clean.sh.

PostgreSQL


Instalación

sudo dnf install -y postgresql postgresql-server

sudo postgresql-setup --initdb --unit postgresql
sudo systemctl start postgresql

Ejecutar psql

sudo -i -u postgres
psql

Configurar postgres y usuarios

CREATE USER mi_usuario WITH PASSWORD 'Mi Contraseña';
psql -U tu_usuario -d tu_base_de_datos

ALTER USER nombre_usuario WITH PASSWORD 'nueva_contraseña'; # Cambiar contraseña de un usuario
ALTER USER postgres WITH PASSWORD 'nueva_contraseña'; # Poner contraseña a postgres de ser necesario
DROP USER nombre_usuario; # Eliminar usuario

Conectar a la base desde afuera

Para conectarte con herramientas como pgAdmin4 o pgModeler.

sudo -i -u postgres
psql
ALTER USER postgres WITH PASSWORD 'nueva_contraseña';
\q

Ir a /var/lib/pgsql/data/pg_hba.conf. Al final del archivo cambia las lineas que dicen:

local all all peer # Original
local all all md5 # Cambio

host all all 127.0.0.1/32 ident # Original (el 127 no va asi, pero se entiende)
host all all 127.0.0.1/32 md5 # Cambio


host all all ::1/128 ident # Original
host all all ::1/128 md5 # Cambio

Luego, en el mismo directorio de datos, abre postgresql.conf y agrega al final:

listen_addresses = 'localhost' # Si no funciona, prueba '*'

Con esto ya está listo. Reinicia el servicio de Postgres y usa la contraseña correcta en la herramienta que vayas a usar.

sudo systemctl restart postgresql # Como usuario normal

Bases de datos

CREATE DATABASE mi_base_de_datos;
GRANT ALL PRIVILEGES ON DATABASE mi_base_de_datos TO mi_usuario;
DROP DATABASE nombre_base_de_datos; # Eliminar base de datos
ALTER DATABASE nombre_base_de_datos RENAME TO nuevo_nombre; # Renombrar base de datos

Comandos

\l; # Muestra todas las bases de datos que existen en tu sistema PostgreSQL.
\dt; # Muestra todas las tablas en la base de datos en la que estás trabajando actualmente.
\c nombre_de_base_de_datos; # Conectarse base de datos
\dt nombre_de_tabla; # Muestra detalles sobre la tabla específica llamada nombre_de_tabla.
\d nombre_de_tabla;
\di nombre_de_tabla; # Indices de una tabla
\q; # Salir de psql
\du; # Ver permisos de usuario

Export and Import

Exportar

pg_dump -U mi_usuario -d mi_base_de_datos -f archivo_de_respaldo.sql

Exportar solo esquema (sin datos):

pg_dump -U usuario -s -d base_de_datos -f esquema.sql

Exportar solo datos (sin esquema):

pg_dump -U usuario -a -d base_de_datos -f datos.sql

Importar

psql -U mi_usuario -d mi_base_de_datos -f archivo_de_respaldo.sql

Tables

CREATE TABLE nombre_tabla (
    columna1 tipo_dato,
    columna2 tipo_dato,
    ...
);
DROP TABLE nombre_tabla; # Borrar tabla
ALTER TABLE nombre_tabla ADD COLUMN nombre_columna tipo_dato; # Agregar una columna a una tabla:
ALTER TABLE nombre_tabla DROP COLUMN nombre_columna; # Eliminar columna de una tabla
ALTER TABLE nombre_tabla RENAME TO nuevo_nombre; # Renombrar tabla

Configuración

La configuración principal se guarda en:

/var/lib/pgsql/data/postgresql.conf

Tipos de datos

  • INTEGER o INT (-/+ 2,147,483,648)

  • BIGINT (-/+ 9,223,372,036,854,775,808)

  • SMALLINT (-/+ 32,768)

  • DECIMAL o NUMERIC (precio DECIMAL(10,2), 10 dígitos en total, 2 después del punto decimal)

  • REAL (Almacena números con precisión simple en coma flotante (menos preciso que DOUBLE PRECISION))

  • DOUBLE PRECISION (Almacena números con mayor precisión en coma flotante)

  • VARCHAR(n) (Longitud variable máxima n)

  • TEXT (Longitud variable sin límite explícito)

  • CHAR(n) (Longitud fija de n)

  • DATE (año, mes, día)

  • TIME

  • TIMESTAMP (Fecha y hora con precisión hasta fracciones de segundo)

  • TIMESTAMPTZ (Con zona horaria)

  • INTERVAL (Periodo de tiempo, diferencia entre dos fechas u horas)

  • BOOLEAN (TRUE, FALSE, NULL)

  • SERIAL (Autoincremental. Usualmente usado en ejemplo: id SERIAL PRIMARY KEY)

  • BIGSERIAL (Lo mismo pero más grande)

  • UUID (Almacena un identificador único universal)

  • JSON

  • JSONB (Lo mismo que json pero en formato binario)

  • XML (Datos en formato xml)

  • BYTEA (Binarios como imágenes o archivos)

  • ARRAY (Lista de valores de tipo determinado, ejemplo: números ARRAY[INTEGER])

  • RANGE (Rango de valores)

Restricciones comunes

Formato: nombre DATA_TYPE RESTRICCION Ej: nombre VARCHAR(100) NOT NULL

  • NOT NULL
  • DEFAULT ‘Valor por defecto’ (estado VARCHAR(10) DEFAULT ‘activo’)
  • UNIQUE (Asegura que los valores de una columna sean únicos (sin duplicados))
  • CHECK (edad INT CHECK (edad >= 18))
  • CONSTRAINT [fk_usuario FOREIGN KEY (usuario_id) REFERENCES usuarios(id)] ( Define una clave foránea para relacionar tablas.)
  • PRIMARY [id SERIAL PRIMARY KEY]

Clave primaria y clave foránea

  • id SERIAL PRIMARY KEY,
  • estudiante_id INT REFERENCES estudiante(id),

JavaFX (OpenJFX)


Dependencias

Tener instalado openjdk

# java-21-openjdk-1:21.0.7.0.6-1.fc42.x86_64
# java-21-openjdk-devel-1:21.0.7.0.6-1.fc42.x86_64
doas dnf install -y java javac 

Instalar Java-fx y configurar

doas dnf install -y openjfx

Usa estos alias

alias javac-fx="javac --module-path /usr/lib/jvm/openjfx/ --add-modules javafx.controls"
alias java-fx="java --module-path /usr/lib/jvm/openjfx/ --add-modules javafx.controls"

Cuidado

Revisar el –module-path con:

find / -name '*openjfx*' 2>/dev/null

Desde Gluon

Descargar la versión deseada, luego extraer y mover el directorio a /.local/share/ Luego en .bash_profile o .zprofile

export PATH_TO_FX="$HOME/.local/share/javafx-sdk-21.0.7/lib"
alias javac-fx="javac --module-path $PATH_TO_FX --add-modules javafx.controls,javafx.fxml,javafx.media"
alias java-fx="java --module-path $PATH_TO_FX --add-modules javafx.controls,javafx.media"

Nushell


Crates.io

Primero sigue esta guía: Instalar Rust.

Si tu distro lo tiene, solo instala nu o nushell. En Fedora:

sudo dnf install nu

Compilar desde fuente

Dependencias

# Debian
sudo apt install pkg-config libssl-dev build-essential

# RedHat/Fedora based
sudo yum install libxcb openssl-devel libX11-devel
cargo install nu --locked

Uso

Eliminar archivos con más de 3 semanas

ls | where modified <= (date now) - 3wk | each {|file| rm $file.name}

Ansible


sudo dnf install ansible

Configurar el inventario

Crear un inventory.ini

[myhosts]
192.0.2.50
192.0.2.51
192.0.2.52

Pendiente

Homebrew


GitHub release

No en Nushell

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(<Homebrew prefix path>/bin/brew shellenv)"

En Nushell

curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | bash

Luego agrega en env.nu

$env.PATH = ($env.PATH | split row (char esep) | prepend '/home/linuxbrew/.linuxbrew/bin')

Ollama


podman run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama

Ejemplo:

podman exec -it ollama ollama run llama3

Alias

alias gemma="podman start ollama && podman exec -it ollama ollama run gemma3:4b"
alias deepseekr1="podman start ollama && podman exec -it ollama ollama run deepseek-r1:8b"
alias qwen="podman start ollama && podman exec -it ollama ollama run qwen3:8b"

Automatización con Woodpecker CI

Este repositorio utiliza Woodpecker CI para compilar y desplegar automáticamente la documentación en Codeberg Pages.

Workflow de Woodpecker

Cada vez que se hace un push a la rama main (o la que se ponga en when), Woodpecker ejecuta los siguientes pasos en un contenedor aislado:

  1. Clone: Descarga el código fuente de main.
  2. Build:
  • Usa una imagen de alpine:edge.
  • Instala mdbook.
  • Compila el libro (genera la carpeta book/ con el HTML).
  1. Publish:
  • Clona la rama pages (donde se aloja el sitio web) en una carpeta temporal.
  • Copia el HTML generado (book/) dentro de esa carpeta.
  • Configura git con identidad de bot.
  • Hace un commit y push de vuelta al repositorio.

Configuración (.woodpecker.yml)

El archivo de configuración se encuentra en la raíz del repositorio.

Puntos clave:

  • when: branch: main: Solo se activa al modificar la rama principal.
  • image: alpine:edge: Usamos Alpine para tener un entorno ligero y rápido.
  • [SKIP CI]: Etiqueta obligatoria en el mensaje de commit del bot para evitar que Woodpecker entre en un bucle infinito al detectar su propio push.

Secretos Requeridos

Para que el despliegue funcione, Woodpecker necesita permisos de escritura. Estos se configuran en Settings -> Secrets (del repositorio o del usuario).

SecretoValorDescripción
codeberg_tokenToken de accesoDebe tener permisos write:repo (o Repository: Read and write). Generado en User Settings -> Applications.
mailEmail para gitSe recomienda usar usuario@noreply.codeberg.org para mantener privacidad.

Lógica de Seguridad

En el paso de publicación, usamos este comando defensivo:

if ! git diff --cached --quiet; then
  git commit -m "chore(deploy): Woodpecker CI ${CI_BUILD_CREATED} [SKIP CI]" && git push;
fi

  • git diff --cached --quiet: Verifica si hubo cambios reales en el HTML generado.
  • if ! ...: Si NO está quieto (hay cambios), procede. Si el sitio es idéntico, no hace nada (evita commits vacíos).
  • [SKIP CI]: Le dice a Woodpecker que ignore este commit y no dispare una nueva compilación.

Rust Cheatsheet para Principiantes (desde C++/Java)


Este cheatsheet se centra en los conceptos fundamentales que necesitas para empezar a ser productivo en Rust, basándose en la tabla que proporcionaste.

1. Rust Básico

Variables y Mutabilidad

Rust prioriza la inmutabilidad por defecto. Usa let para declarar variables. Para hacerlas mutables, añade mut. Los tipos se infieren a menudo, pero puedes especificarlos.

  • Inmutable:
    #![allow(unused)]
    fn main() {
    let x: i32 = 5; // x es inmutable
    let y = 10;    // Tipo i32 inferido, y es inmutable
    // x = 6; // Error! No se puede reasignar una variable inmutable
    }
  • Mutable:
    #![allow(unused)]
    fn main() {
    let mut z = 15; // z es mutable
    z = 20;         // ¡Ok!
    println!("z es: {}", z);
    }
  • Constantes (siempre inmutables, tipo debe ser anotado, evaluadas en tiempo de compilación):
    #![allow(unused)]
    fn main() {
    const MAX_POINTS: u32 = 100_000;
    }
  • Shadowing (puedes declarar una nueva variable con el mismo nombre, incluso cambiando el tipo):
    #![allow(unused)]
    fn main() {
    let spaces = "   ";
    let spaces = spaces.len(); // Ahora 'spaces' es un número (3)
    }

Tipos de Datos Comunes

  • Enteros: i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize (tamaño de puntero).
  • Flotantes: f32, f64 (por defecto f64).
  • Booleanos: bool (true, false).
  • Caracteres: char (Unicode, 4 bytes).
  • Tuplas: Colección fija de diferentes tipos.
    #![allow(unused)]
    fn main() {
    let tup: (i32, f64, u8) = (500, 6.4, 1);
    let (x, y, z) = tup; // Destructuración
    println!("El valor de y es: {}", y); // 6.4
    println!("El primer valor es: {}", tup.0); // Acceso por índice
    }
  • Arrays: Colección fija del mismo tipo, en el stack.
    #![allow(unused)]
    fn main() {
    let a = [1, 2, 3, 4, 5];
    let first = a[0];
    // let b: [i32; 5] = [1, 2, 3, 4, 5]; // Con anotación de tipo y tamaño
    // a[0] = 10; // Error si 'a' no es mutable
    }
  • Strings:
    • &str (string slice): Inmutable, referencia a datos de string (usualmente en el binario o en el heap).
      #![allow(unused)]
      fn main() {
      let s_literal = "hola"; // &str
      }
    • String: Mutable, buffer de string en el heap. Similar a std::string en C++ o String en Java.
      #![allow(unused)]
      fn main() {
      let mut s_heap = String::from("hola");
      s_heap.push_str(", mundo!");
      println!("{}", s_heap); // hola, mundo!
      }

Funciones

Declaradas con fn. Los tipos de los parámetros y el tipo de retorno (si lo hay) deben ser especificados. La última expresión en una función es su valor de retorno implícito si no se usa return.

fn saludar(nombre: &str) {
    println!("Hola, {}!", nombre);
}

fn sumar(a: i32, b: i32) -> i32 {
    a + b // No se necesita ';' ni 'return' si es la última expresión
}

fn main() {
    saludar("Mundo");
    let resultado = sumar(5, 3);
    println!("5 + 3 = {}", resultado);
}

Control de Flujo

  • if/else if/else: Similar a C++/Java. Las condiciones deben ser bool. if es una expresión.
    #![allow(unused)]
    fn main() {
    let numero = 6;
    if numero % 4 == 0 {
        println!("El número es divisible por 4");
    } else if numero % 3 == 0 {
        println!("El número es divisible por 3");
    } else {
        println!("El número no es divisible ni por 4 ni por 3");
    }
    
    let condicion = true;
    let valor = if condicion { 5 } else { 6 }; // 'if' como expresión
    println!("El valor es: {}", valor);
    }
  • Bucles:
    • loop: Bucle infinito (usa break para salir).
      #![allow(unused)]
      fn main() {
      let mut contador = 0;
      let resultado_loop = loop {
          contador += 1;
          if contador == 10 {
              break contador * 2; // 'break' puede devolver un valor
          }
      };
      println!("El resultado del loop es {}", resultado_loop); // 20
      }
    • while: Bucle condicional.
      #![allow(unused)]
      fn main() {
      let mut numero = 3;
      while numero != 0 {
          println!("{}!", numero);
          numero -= 1;
      }
      println!("¡DESPEGUE!");
      }
    • for: Para iterar sobre colecciones (más común y seguro).
      #![allow(unused)]
      fn main() {
      let a = [10, 20, 30, 40, 50];
      for elemento in a.iter() { // .iter() crea un iterador sobre referencias
          println!("El valor es: {}", elemento);
      }
      
      for numero in (1..4).rev() { // Rango (1, 2, 3) en reversa
          println!("{}!", numero);
      }
      }

Módulos

Para organizar el código.

// En lib.rs o main.rs
mod mi_modulo {
    pub fn funcion_publica() {
        println!("Llamada a funcion_publica()");
        funcion_privada();
    }

    fn funcion_privada() {
        println!("Llamada a funcion_privada()");
    }

    pub mod sub_modulo {
        pub fn otra_funcion() {
            println!("Llamada a otra_funcion() en sub_modulo");
        }
    }
}

fn main() {
    // Ruta completa
    crate::mi_modulo::funcion_publica();
    // Usando 'use'
    use crate::mi_modulo::sub_modulo::otra_funcion;
    otra_funcion();

    // Si 'mi_modulo' está en otro archivo llamado 'mi_modulo.rs'
    // mod mi_modulo; // En main.rs o lib.rs para declarar el módulo
    // mi_modulo::funcion_publica();
}
  • crate: Raíz del crate (paquete).
  • pub: Hace un ítem público. Por defecto, todo es privado.
  • use: Importa ítems a un scope.

2. Gestión de Paquetes con Cargo

Cargo es el gestor de paquetes y sistema de construcción de Rust.

  • Crear un nuevo proyecto:
    cargo new mi_proyecto      # Crea una aplicación binaria
    cargo new --lib mi_libreria # Crea una librería
    
  • Estructura típica del proyecto:
    mi_proyecto/
    ├── Cargo.toml  # Manifiesto del paquete (metadatos, dependencias)
    ├── src/
    │   └── main.rs   # Código fuente principal para binarios
    │   # O lib.rs para librerías
    
  • Comandos comunes de Cargo:
    • cargo build: Compila el proyecto (en target/debug/).
    • cargo build --release: Compila con optimizaciones (en target/release/).
    • cargo run: Compila y ejecuta el binario.
    • cargo test: Ejecuta las pruebas.
    • cargo check: Comprueba el código sin generar un ejecutable (más rápido).
    • cargo doc --open: Genera y abre la documentación.
    • cargo add <crate_name>: Añade una dependencia a Cargo.toml.
  • Cargo.toml (ejemplo básico):
    [package]
    name = "mi_proyecto"
    version = "0.1.0"
    edition = "2021" # Edición de Rust
    
    [dependencies]
    # rand = "0.8.5" # Ejemplo de dependencia de crates.io
    # ratatui = { version = "0.26.0", features = ["crossterm"] }
    # crossterm = "0.27.0"
    

3. Propiedad y Préstamos (Ownership & Borrowing)

Este es el concepto más distintivo de Rust. Asegura la seguridad de memoria sin un recolector de basura.

Reglas de Propiedad (Ownership)

  1. Cada valor en Rust tiene una variable que es su dueña (owner).
  2. Solo puede haber un dueño a la vez.
  3. Cuando el dueño sale del ámbito (scope), el valor se libera (dropped).
#![allow(unused)]
fn main() {
{
    let s1 = String::from("hola"); // s1 es dueña de "hola"

    // let s2 = s1; // ¡MOVIMIENTO! s1 ya no es válida.
                  // Similar a std::unique_ptr en C++ (sin copia implícita)
                  // Para tipos simples como i32, se copian (implementan el trait 'Copy')

    let s2 = s1.clone(); // Copia profunda (heap data copiado)
    println!("s1 = {}, s2 = {}", s1, s2); // Ambas válidas
} // s1 (si no fue movida) y s2 salen del scope, la memoria se libera.
}

Préstamos y Referencias (Borrowing & References)

Permiten acceder a datos sin tomar posesión.

  • Referencias Inmutables (&T):
    • Puedes tener múltiples referencias inmutables a un dato.
    • No puedes modificar el dato a través de ellas.
    #![allow(unused)]
    fn main() {
    let s1 = String::from("hola");
    let len = calcular_longitud(&s1); // Se presta s1 inmutablemente
    println!("La longitud de '{}' es {}.", s1, len);
    
    fn calcular_longitud(s: &String) -> usize { // s es una referencia a un String
        s.len()
    } // s sale del scope, pero no libera nada porque no es dueña
    }
  • Referencias Mutables (&mut T):
    • Solo puedes tener una referencia mutable a un dato en un scope particular.
    • Esto previene data races en tiempo de compilación.
    • No puedes tener referencias inmutables si existe una mutable.
    #![allow(unused)]
    fn main() {
    let mut s = String::from("hola");
    cambiar(&mut s);
    println!("{}", s); // "hola, mundo"
    
    fn cambiar(algun_string: &mut String) {
        algun_string.push_str(", mundo");
    }
    }
    Restricción importante:
    #![allow(unused)]
    fn main() {
    let mut s = String::from("hello");
    let r1 = &s; // Referencia inmutable, OK
    let r2 = &s; // Otra referencia inmutable, OK
    // let r3 = &mut s; // ¡ERROR! No puedes tener una referencia mutable mientras existan inmutables
    // println!("{}, {}, and {}", r1, r2, r3);
    
    let mut s_mut = String::from("hello");
    let r_mut1 = &mut s_mut;
    // let r_mut2 = &mut s_mut; // ¡ERROR! Solo una referencia mutable a la vez
    // println!("{}, {}", r_mut1, r_mut2);
    }

Lifetimes (Tiempos de Vida) 'a

Aseguran que las referencias sean siempre válidas. A menudo son inferidos por el compilador. Los necesitas explícitamente cuando las relaciones de lifetimes entre referencias no son obvias para el compilador, especialmente en firmas de funciones y structs que contienen referencias.

  • Objetivo: Evitar dangling references (referencias que apuntan a memoria que ha sido liberada).
  • Ejemplo donde se necesitan:
    // Devuelve una referencia, el compilador necesita saber si vive tanto como 'x' o 'y'
    fn el_mas_largo<'a>(x: &'a str, y: &'a str) -> &'a str {
        if x.len() > y.len() {
            x
        } else {
            y
        }
    }
    
    fn main() {
        let string1 = String::from("cadena larga es larga");
        {
            let string2 = String::from("xyz");
            let resultado = el_mas_largo(string1.as_str(), string2.as_str());
            println!("La cadena más larga es {}", resultado);
        } // string2 se libera aquí. Si resultado apuntara a string2, sería un dangling reference.
          // Pero el lifetime 'a' del resultado está atado al más corto de string1 y string2.
    }
    La idea es que el dato referenciado por 'a debe vivir al menos tanto como la referencia anotada con 'a.

4. POO en Rust (Estilo Rust)

Rust no tiene “clases” como Java/C++, pero ofrece estructuras (structs), enumeraciones (enums), y comportamientos (traits) para lograr encapsulación y polimorfismo.

struct (Estructuras)

Agrupan datos relacionados. Similar a struct en C o los campos de una clase en Java/C++.

struct Usuario {
    activo: bool,
    nombre_usuario: String,
    email: String,
    contador_sesion: u64,
}

fn main() {
    let mut usuario1 = Usuario {
        email: String::from("alguien@ejemplo.com"),
        nombre_usuario: String::from("alguien123"),
        activo: true,
        contador_sesion: 1,
    };

    usuario1.email = String::from("otroemail@ejemplo.com");
    println!("Email: {}", usuario1.email);

    let usuario2 = construir_usuario(
        String::from("usuario2@ejemplo.com"),
        String::from("usuario2")
    );
}

fn construir_usuario(email: String, nombre_usuario: String) -> Usuario {
    Usuario {
        email, // Abreviatura si el nombre del parámetro y el campo son iguales
        nombre_usuario,
        activo: true,
        contador_sesion: 1,
    }
}

// Structs tupla (sin nombres de campo)
struct Color(i32, i32, i32);
struct Punto(i32, i32, i32);

let negro = Color(0, 0, 0);
let origen = Punto(0, 0, 0);
println!("Primer valor de negro: {}", negro.0);

impl (Implementación de Métodos)

Define métodos para structs y enums.

struct Rectangulo {
    ancho: u32,
    alto: u32,
}

// Bloque de implementación para Rectangulo
impl Rectangulo {
    // Método (toma &self, &mut self, o self)
    fn area(&self) -> u32 { // &self es una referencia inmutable a la instancia
        self.ancho * self.alto
    }

    fn puede_contener(&self, otro: &Rectangulo) -> bool {
        self.ancho > otro.ancho && self.alto > otro.alto
    }

    // Función asociada (no toma self), a menudo usada como constructor
    // Similar a un método estático en Java/C++
    fn cuadrado(tamano: u32) -> Self { // Self es un alias para Rectangulo
        Self { ancho: tamano, alto: tamano }
    }
}

fn main() {
    let rect1 = Rectangulo { ancho: 30, alto: 50 };
    let rect2 = Rectangulo { ancho: 10, alto: 40 };
    let rect_cuadrado = Rectangulo::cuadrado(25); // Llamada a función asociada

    println!("El área del rectángulo es {} pixeles cuadrados.", rect1.area());
    println!("¿Puede rect1 contener a rect2? {}", rect1.puede_contener(&rect2));
    println!("Área del cuadrado: {}", rect_cuadrado.area());
}

enum (Enumeraciones)

Tipos que pueden ser uno de varios valores posibles (variantes). Las variantes pueden tener datos asociados. Son mucho más potentes que los enums de C/C++ y Java (más cercanos a uniones discriminadas o tipos algebraicos de datos).

enum Mensaje {
    Salir,                       // Sin datos asociados
    Mover { x: i32, y: i32 },    // Con campos nombrados (como un struct)
    Escribir(String),            // Con un String
    CambiarColor(i32, i32, i32), // Con una tupla de datos
}

impl Mensaje {
    fn procesar(&self) {
        match self {
            Mensaje::Salir => println!("Saliendo..."),
            Mensaje::Mover { x, y } => {
                println!("Moviendo a x: {}, y: {}", x, y);
            }
            Mensaje::Escribir(texto) => {
                println!("Mensaje de texto: {}", texto);
            }
            Mensaje::CambiarColor(r, g, b) => {
                println!("Cambiando color a R:{}, G:{}, B:{}", r, g, b);
            }
        }
    }
}

fn main() {
    let msg1 = Mensaje::Mover { x: 10, y: 20 };
    let msg2 = Mensaje::Escribir(String::from("Hola enum"));
    msg1.procesar();
    msg2.procesar();
}

trait (Rasgos)

Definen un conjunto de métodos que un tipo puede implementar. Similar a interfaces en Java o clases base puramente virtuales en C++. Permiten el polimorfismo.

// Definición de un trait
pub trait Resumible {
    fn resumir_autor(&self) -> String; // Método que debe ser implementado

    fn resumir(&self) -> String { // Método con implementación por defecto
        format!("(Leer más de {}...)", self.resumir_autor())
    }
}

pub struct Noticia {
    pub titular: String,
    pub autor: String,
    pub contenido: String,
}

// Implementación del trait Resumible para Noticia
impl Resumible for Noticia {
    fn resumir_autor(&self) -> String {
        format!("@{}", self.autor)
    }
    // Podríamos sobreescribir resumir() aquí si quisiéramos
}

pub struct Tweet {
    pub nombre_usuario: String,
    pub contenido: String,
    pub respuesta: bool,
    pub retweet: bool,
}

impl Resumible for Tweet {
    fn resumir_autor(&self) -> String {
        format!("@{}", self.nombre_usuario)
    }

    fn resumir(&self) -> String {
        format!("{}: {}", self.nombre_usuario, self.contenido)
    }
}

// Polimorfismo usando traits (parámetros genéricos con trait bounds)
pub fn notificar<T: Resumible>(item: &T) {
    println!("¡Noticia de última hora! {}", item.resumir());
}

// Polimorfismo usando trait objects (dinámico)
pub fn notificar_dinamico(item: &dyn Resumible) {
    println!("¡Noticia dinámica! {}", item.resumir());
}

fn main() {
    let tweet = Tweet {
        nombre_usuario: String::from("caballo_ebooks"),
        contenido: String::from("por supuesto, como ustedes saben, la gente"),
        respuesta: false,
        retweet: false,
    };

    let articulo = Noticia {
        titular: String::from("¡Los pingüinos ganan la Stanley Cup!"),
        autor: String::from("Iceburgh"),
        contenido: String::from("El equipo de hockey de Pittsburgh, los Pingüinos..."),
    };

    println!("1 nuevo tweet: {}", tweet.resumir());
    println!("Nuevo artículo disponible: {}", articulo.resumir());

    notificar(&tweet);
    notificar_dinamico(&articulo);
}

5. Tratamiento de Errores

Rust no tiene excepciones como Java o C++. En su lugar, usa tipos para representar posibles errores.

Option<T>

Para valores que pueden ser opcionales (o estar ausentes). Similar a Optional<T> en Java 8+.

  • Variantes: Some(T) (el valor está presente) o None (el valor está ausente).
fn encontrar_caracter(texto: &str, caracter_buscado: char) -> Option<usize> {
    for (indice, caracter_actual) in texto.char_indices() {
        if caracter_actual == caracter_buscado {
            return Some(indice); // Valor encontrado
        }
    }
    None // Valor no encontrado
}

fn main() {
    let texto = "hola mundo";
    match encontrar_caracter(texto, 'm') {
        Some(indice) => println!("'m' encontrada en el índice: {}", indice),
        None => println!("'m' no encontrada."),
    }

    match encontrar_caracter(texto, 'z') {
        Some(indice) => println!("'z' encontrada en el índice: {}", indice),
        None => println!("'z' no encontrada."),
    }

    // 'if let' es una forma concisa de manejar una variante de Option/Result
    if let Some(indice) = encontrar_caracter(texto, 'o') {
        println!("'o' encontrada con if let en: {}", indice);
    }

    // Métodos útiles de Option:
    // unwrap(): Devuelve el valor en Some(T) o hace panic! si es None (¡usar con cuidado!)
    // unwrap_or(default_value): Devuelve el valor o un valor por defecto.
    // unwrap_or_else(closure): Devuelve el valor o el resultado de una clausura.
    // map(closure): Aplica una función al valor dentro de Some.
    // and_then(closure): Encadena operaciones que devuelven Option.
    let quizas_numero: Option<i32> = Some(5);
    let _numero_mas_uno = quizas_numero.map(|n| n + 1); // Some(6)
    let _otro_numero = None::<i32>.unwrap_or(0); // 0
}

Result<T, E>

Para operaciones que pueden fallar (éxito o error). T es el tipo del valor en caso de éxito, E es el tipo del error.

  • Variantes: Ok(T) (operación exitosa) o Err(E) (operación fallida).
use std::fs::File;
use std::io::{self, Read};

// Función que devuelve un Result
fn leer_archivo(nombre_archivo: &str) -> Result<String, io::Error> {
    let mut f = match File::open(nombre_archivo) {
        Ok(archivo) => archivo,
        Err(e) => return Err(e), // Propaga el error temprano
    };

    let mut s = String::new();
    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

// Usando el operador '?' para propagar errores (más idiomático)
// '?' solo puede usarse en funciones que devuelven Result o Option.
fn leer_archivo_con_interrogante(nombre_archivo: &str) -> Result<String, io::Error> {
    let mut f = File::open(nombre_archivo)?; // Si es Err, retorna Err(e) desde esta función
    let mut s = String::new();
    f.read_to_string(&mut s)?; // Si es Err, retorna Err(e)
    Ok(s) // Si todo va bien, retorna Ok(s)

    // Incluso más corto:
    // std::fs::read_to_string(nombre_archivo)
}

fn main() {
    match leer_archivo_con_interrogante("hola.txt") {
        Ok(contenido) => println!("Contenido del archivo: {}", contenido),
        Err(error) => println!("Error al leer el archivo: {:?}", error),
    }

    // expect(): Similar a unwrap(), pero con un mensaje de panic personalizado.
    // let _contenido = File::open("no_existe.txt").expect("Falló al abrir no_existe.txt");
}

El operador ? desenvuelve Ok(T) a T o retorna Err(E) de la función actual.


6. Asincronía (Básico) (Opcional, según tu proyecto TUI)

Si tu TUI necesita realizar operaciones de I/O (red, disco) sin bloquear el hilo principal, necesitarás asincronía.

  • async fn: Define una función asíncrona. Devuelve un Future.
  • .await: Espera a que un Future se complete sin bloquear el hilo. Solo se puede usar dentro de una async fn.
// Este es un ejemplo conceptual. Necesitarías un runtime como tokio o async-std.
// Añade a Cargo.toml:
// tokio = { version = "1", features = ["full"] }

/*
async fn obtener_datos_web(url: &str) -> Result<String, reqwest::Error> {
    // reqwest es una librería popular para HTTP, también asíncrona
    let respuesta = reqwest::get(url).await?;
    let cuerpo = respuesta.text().await?;
    Ok(cuerpo)
}

async fn tarea_larga() {
    println!("Iniciando tarea larga...");
    // Simula trabajo, como una llamada de red
    tokio::time::sleep(std::time::Duration::from_secs(2)).await;
    println!("Tarea larga completada.");
}

// En tu función main (o una función marcada con el macro del runtime)
#[tokio::main] // Si usas tokio
async fn main() {
    println!("Iniciando programa asíncrono.");

    let handle1 = tokio::spawn(async { // Ejecuta en una nueva "tarea" (green thread)
        tarea_larga().await;
    });

    let handle2 = tokio::spawn(async {
        match obtener_datos_web("https://www.rust-lang.org").await {
            Ok(pagina) => println!("Página obtenida (primeros 100 chars): {:.100}", pagina),
            Err(e) => eprintln!("Error al obtener la página: {}", e),
        }
    });

    println!("Tareas iniciadas, esperando...");
    // Espera a que todas las tareas spawneadas terminen
    let _ = tokio::try_join!(handle1, handle2);
    println!("Programa asíncrono finalizado.");
}
*/
  • Runtimes asíncronos (tokio, async-std): Proveen el ejecutor para los Futures, manejo de I/O, timers, etc.
    • tokio es muy popular, especialmente para networking.
    • async-std busca ser un análogo asíncrono de la librería estándar.

7. Ratatui + Crossterm (Específico para TUI)

Estas bibliotecas te ayudarán a construir tu Interfaz de Usuario en Terminal (TUI).

  • Crossterm: Proporciona funcionalidades de bajo nivel para interactuar con la terminal (manipulación del cursor, colores, entrada de teclado/ratón, modo raw). Ratatui lo usa como backend.
  • Ratatui: Es una biblioteca para construir TUIs, inspirada en React. Se basa en dibujar “widgets” en un “buffer” y luego mostrar ese buffer en la terminal.
    • Ciclo principal (conceptual):
      1. Inicializar la terminal (usando Crossterm).
      2. Entrar en un bucle: a. Leer eventos de entrada (teclado, ratón) de forma no bloqueante (Crossterm). b. Actualizar el estado de tu aplicación según la entrada. c. Dibujar la UI en un Frame de Ratatui: i. Definir Layouts para dividir el área de la terminal. ii. Renderizar Widgets en las áreas del layout. d. Si el usuario quiere salir, romper el bucle.
      3. Restaurar la terminal.

Conceptos Clave de Ratatui:

  • Terminal: El objeto principal para interactuar con la terminal.
  • Frame: Se pasa a tu función de dibujado en cada iteración, es donde dibujas.
  • Layout: Define cómo dividir un área rectangular en sub-áreas.
    • Direction: Horizontal o Vertical.
    • Constraint: Define el tamaño de cada celda del layout (Percentage, Length, Min, Max).
    #![allow(unused)]
    fn main() {
    // Ejemplo de Layout
    // use ratatui::layout::{Layout, Direction, Constraint, Rect};
    // fn ui(frame: &mut Frame) {
    //     let chunks = Layout::default()
    //         .direction(Direction::Vertical)
    //         .margin(1)
    //         .constraints(
    //             [
    //                 Constraint::Percentage(10), // 10% para el título
    //                 Constraint::Percentage(80), // 80% para el contenido
    //                 Constraint::Percentage(10), // 10% para el pie
    //             ]
    //             .as_ref(),
    //         )
    //         .split(frame.size()); // frame.size() es el Rect de toda la terminal
    //     // chunks[0] es el Rect para el título, chunks[1] para contenido, etc.
    // }
    }
  • Widget: Componentes visuales. Son structs que implementan el trait Widget.
    • Block: Un contenedor con bordes opcionales y título. A menudo envuelve a otros widgets.
    • Paragraph: Para mostrar texto, con opciones de alineación y autoajuste.
    • List: Para mostrar una lista de ítems.
    • Tabs: Para crear una interfaz con pestañas.
    • Muchos más: Table, Chart, Gauge, Sparkline, etc.
    #![allow(unused)]
    fn main() {
    // Ejemplo de Widget (dentro de la función ui)
    // use ratatui::widgets::{Block, Borders, Paragraph};
    // use ratatui::text::Text;
    //
    // // En chunks[0] (definido arriba)
    // let titulo = Paragraph::new(Text::styled("Mi TUI con Ratatui", Style::default().fg(Color::Yellow)))
    //     .block(Block::default().borders(Borders::ALL))
    //     .alignment(Alignment::Center);
    // frame.render_widget(titulo, chunks[0]);
    //
    // // En chunks[1]
    // let contenido_texto = "Este es el contenido principal...\nPresiona 'q' para salir.";
    // let parrafo_contenido = Paragraph::new(contenido_texto)
    //     .block(Block::default().title("Contenido").borders(Borders::ALL));
    // frame.render_widget(parrafo_contenido, chunks[1]);
    }
  • Style: Para definir colores (foreground, background) y modificadores (bold, italic).
  • Eventos (con Crossterm):
    #![allow(unused)]
    fn main() {
    // use crossterm::event::{self, Event as CrosstermEvent, KeyCode, KeyEvent};
    // loop {
    //     // Esperar un evento por un tiempo máximo (para no bloquear indefinidamente)
    //     if crossterm::event::poll(std::time::Duration::from_millis(50))? {
    //         if let CrosstermEvent::Key(key_event) = event::read()? {
    //             match key_event.code {
    //                 KeyCode::Char('q') => break, // Salir del bucle
    //                 KeyCode::Up => { /* mover selección hacia arriba */ },
    //                 KeyCode::Down => { /* mover selección hacia abajo */ },
    //                 // ... otros KeyCode
    //                 _ => {}
    //             }
    //         } else if let CrosstermEvent::Mouse(mouse_event) = event::read()? {
    //             // Procesar eventos de ratón (posición, clics)
    //             // mouse_event.kind, mouse_event.column, mouse_event.row
    //         }
    //     }
    //     // Lógica de la app y dibujar UI aquí
    //     // terminal.draw(|f| ui(f, &app_state))?;
    // }
    }

Configuración inicial para Ratatui + Crossterm:

  1. Añade a Cargo.toml:
    [dependencies]
    ratatui = { version = "0.27.0", features = ["crossterm"] } # O la versión más reciente
    crossterm = "0.27.0"                                  # O la versión más reciente
    
  2. Código básico de inicialización/restauración:
    // En tu main.rs
    /*
    use std::io;
    use ratatui::Terminal;
    use ratatui::backend::CrosstermBackend;
    use crossterm::{terminal::{enable_raw_mode, disable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, execute};
    
    fn main() -> Result<(), Box<dyn std::error::Error>> {
        // Setup terminal
        enable_raw_mode()?; // Entrar en modo raw para control total de entrada
        let mut stdout = io::stdout();
        execute!(stdout, EnterAlternateScreen)?; // Cambiar a una pantalla alternativa
        let backend = CrosstermBackend::new(stdout);
        let mut terminal = Terminal::new(backend)?;
    
        // Bucle principal de la aplicación aquí...
        // loop {
        //    terminal.draw(|f| {
        //        // ui(f, &app_state); // Tu función de dibujado
        //    })?;
        //    // Manejo de eventos aquí...
        //    // if quit { break; }
        // }
    
        // Restaurar terminal
        disable_raw_mode()?;
        execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
        // terminal.show_cursor()?; // Si lo ocultaste
    
        Ok(())
    }
    */

Herramientas de Rust


Primero instala rustup

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup update
rustup component add rust-analyzer

Seguridad

cargo install cargo-audit
cargo install cargo-update
cargo install cargo-download

Cómo revisar con cargo audit

cargo download pkg > pkg.gz
tar -xvf pkg.gz
cd pkg*
cargo audit

Cómo usar cargo-update

cargo install-update -l

Instalar paquetes

# Buscar dependencias si es necesario
cargo install paquete
cargo install --locked paquete

Cargo (Rust)


Cargo es el gestor de paquetes y sistema de build de Rust. Sirve para crear proyectos, compilar, ejecutar, testear y manejar dependencias.

Crear proyecto

# Binario
cargo new mi_app

# Librería
cargo new mi_lib --lib

# Inicializar en un directorio existente
cargo init

Estructura básica

  • Cargo.toml: configuración y dependencias.
  • Cargo.lock: versiones exactas de dependencias.
  • src/main.rs: entrada de binarios.
  • src/lib.rs: entrada de librerías.

Comandos básicos

# Compilar en debug (por defecto)
cargo build

# Compilar optimizado
cargo build --release

# Ejecutar
cargo run

# Pasar argumentos a tu programa
cargo run -- --help

# Ver errores rápido sin generar binario
cargo check

# Tests
cargo test

# Formato y lints
cargo fmt
cargo clippy

Dependencias

Editar Cargo.toml y agregar en [dependencies]:

[dependencies]
serde = "1"

Luego:

cargo build

Instalar herramientas

# Instalar un binario global (por ejemplo ripgrep)
cargo install ripgrep

# Actualizar dependencias del proyecto
cargo update

Tips

  • Si algo tarda mucho en compilar, usa cargo check mientras iteras.
  • Para generar documentación: cargo doc --open.

Rust Coreutils


En Fedora:

sudo dnf install uutils-coreutils
# Recomendado
sudo dnf install bat ripgrep zoxide nu skim

Modificar el PATH por ejemplo en .bash_profile

export PATH="/usr/libexec/uutils-coreutils:$HOME:$PATH"

RustScan


Crates.io

Instalación

Primero instala Nmap. En Fedora:

sudo dnf install nmap

Configurar Rustup/Cargo Luego:

cargo install rustscan

Consejos

Para revisar puertos abiertos

rustscan -a <ip-local> --ulimit 5000
rustscan -a 192.168.x.y --ulimit 5000

TLDR

 Escáner de puertos moderno escrito en Rust.
  Nota: `nmap` debe estar instalado para que funcionen algunos ejemplos.
  Más información: <https://github.com/bee-san/RustScan/wiki>.

  Escanear todos los puertos de una o más direcciones separadas por comas:

      rustscan [-a|--addresses] ip_or_hostname

  Escanear los top 1000 puertos con detección de servicio y versión:

      rustscan --top [-a|--addresses] address_or_addresses

  Escanear una lista específica de puertos:

      rustscan [-p|--ports] port1,port2,... [-a|--addresses] address_or_addresses

  Escanear un rango específico de puertos:

      rustscan [-r|--range] start-end [-a|--addresses] address_or_addresses

  Invocar funciones de `nmap` (detección de SO y scripts por defecto):

      rustscan [-a|--addresses] address_or_addresses -- -O [-sC|--script=default]

  Escanear con batch size y timeout personalizados (default: 4500 y 1500ms):

      rustscan [-b|--batch-size] batch_size [-t|--timeout] timeout [-a|--addresses] address_or_addresses

  Escanear con orden específico de puertos:

      rustscan --scan-order serial|random [-a|--addresses] address_or_addresses

  Escanear en modo greppable (solo puertos, sin `nmap`):

      rustscan [-g|--greppable] [-a|--addresses] address_or_addresses

Podman


Podman

Crear contenedor básico

podman run -it --name prueba-debian --hostname debi debian
  • -it para terminal interactivo
  • --name nombre del contenedor
  • --hostname hostname dentro del contenedor

Copiar archivo del host al contenedor

podman cp /ruta/en/host/mi_archivo.txt nombre-contenedor:/ruta/destino/

Crear usuario con sudo en Debian

apt update && apt install -y sudo
useradd -m -s /bin/bash devuser
usermod -aG sudo devuser
echo "devuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
su - devuser

Entrar a un contenedor creado

# Usuario root (por defecto)
podman exec -it nombre_contenedor bash

# Usuario específico
podman exec -it --user usuario nombre_contenedor bash

# Ejemplo con usuario creado:
podman exec -it --user devuser prueba-debian bash

GUI

X11

 podman run -it --rm \
  -v /tmp/.X11-unix:/tmp/.X11-unix:ro \
  -e DISPLAY=$DISPLAY \
  --security-opt label=type:container_runtime_t \
  --name test \
  debian \
  /bin/bash

Wayland (no probado)

podman run -it --rm \
  -v "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY:/tmp/wayland-0" \
  -e XDG_RUNTIME_DIR=/tmp \
  -e WAYLAND_DISPLAY=wayland-0 \
  --security-opt label=type:container_runtime_t \
  docker.io/library/debian:latest \
  sh -c "apt update && apt install -y weston && weston --socket=wayland-0"

¿Qué hace cada parte?

-v "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY:/tmp/wayland-0"
Monta el socket de Wayland del host en el contenedor.

-e XDG_RUNTIME_DIR=/tmp
Configura el directorio runtime dentro del contenedor.

-e WAYLAND_DISPLAY=wayland-0
Define el nombre del socket Wayland.

--security-opt label=type:container_runtime_t
Política de SELinux segura (mejor que label=disable).

sh -c "..."
Instala solo lo necesario y ejecuta Weston (compositor minimalista).

Containers

podman run -it \
  --name bllsht \
  --hostname fedora \
  -v "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY:/tmp/wayland-0" \
  -e XDG_RUNTIME_DIR=/tmp \
  -e WAYLAND_DISPLAY=wayland-0 \
  --security-opt label=type:container_runtime_t \
  fedora

EN PODMAN DESKTOP

Volumes: /run/user/1000/wayland-1 : /tmp/wayland-0

ENV:

XDG_RUNTIME_DIR : /tmp WAYLAND_DISPLAY : wayland-0 QT_QPA_PLATFORM : wayland

PARA EL DE KEEPASS AGREGAR ESTE ENV

KVM


systemctl enable --now libvirtd
usermod -aG libvirt user
firewall-cmd --add-service=libvirt --permanent

sed -i 's/#unix_sock_group = "libvirt"/unix_sock_group = "libvirt"/' /etc/libvirt/libvirtd.conf
sed -i 's/#auth_unix_ro = "none"/auth_unix_ro = "none"/' /etc/libvirt/libvirtd.conf

sed -i '
  /^#.*unix_sock_group = "libvirt"/s/^#//
  s/unix_sock_ro_perms = "0777"/unix_sock_ro_perms = "0770"/
  s/^#auth_unix_ro = "none"/auth_unix_ro = "polkit"/
  s/^#auth_unix_rw = "none"/auth_unix_rw = "polkit"/
' /etc/libvirt/libvirtd.conf

En kvm activar edicion de xml, y en la distro a eleccion ir a la network poner xml y em vez de network poner user arriba Para que rinda perfecto poner spice server y video con qxl

Whonix KVM


Tux

KVM/Libvirt

Ver: KVM

Descarga

Aceptar licencia

tar -xvf Whonix*.libvirt.xz
touch WHONIX_BINARY_LICENSE_AGREEMENT_accepted 

Importar plantillas de VM

  • Agregar las redes virtuales:
sudo virsh -c qemu:///system net-define Whonix_external*.xml ;
sudo virsh -c qemu:///system net-define Whonix_internal*.xml
  • Activar las redes virtuales:
sudo virsh -c qemu:///system net-autostart Whonix-External ;
sudo virsh -c qemu:///system net-start Whonix-External ;
sudo virsh -c qemu:///system net-autostart Whonix-Internal ;
sudo virsh -c qemu:///system net-start Whonix-Internal 
  • Importar las imágenes de Whonix Gateway y Workstation:
sudo virsh -c qemu:///system define Whonix-Gateway*.xml ;
sudo virsh -c qemu:///system define Whonix-Workstation*.xml 

Instalación por archivos de imagen

  • Opción 1: Lenta
sudo mv Whonix-Gateway*.qcow2 /var/lib/libvirt/images/Whonix-Gateway.qcow2 ;
sudo mv Whonix-Workstation*.qcow2 /var/lib/libvirt/images/Whonix-Workstation.qcow2 
  • Opción 2: Recomendada Como root:
sudo su
cp Whonix*.qcow2.libvirt.xz /var/lib/libvirt/images/
cd /var/lib/libvirt/images/
tar -xvf Whonix*.qcow2.libvirt.xz 
rm WH* Wh*.xml Wh*.xz
mv Whonix-Workstation*.qcow2 Whonix-Workstation.qcow2
mv Whonix-Gateway*.qcow2 Whonix-Gateway.qcow2

Extra

Solo modificar cosas como RAM o CPU.

Pasar archivos

Existen 2 formas:

  • virtio-9p: más antigua y más lenta
  • virtio-fs: más nueva y rápida. A costa de activar Shared memory, lo que puede afectar la seguridad, así que ir con precaución.

Settings -> Add hardware -> Filesystem -> virtio-9p/virtio-fs

Brave en Wayland


Ir a /usr/share/applications/brave-browser.desktop Y cambiar todas las líneas que tengan Exec con –enable-features=UseOzonePlatform –ozone-platform=wayland. Por ejemplo:

Exec=brave-browser --enable-features=UseOzonePlatform --ozone-platform=wayland %U

Mullvad VPN en Wayland

Ir a /usr/share/applications/mullvad-vpn.desktop Y cambiar todas las líneas que tengan Exec con –enable-features=UseOzonePlatform,WaylandWindowDecorations –ozone-platform=wayland. Por ejemplo:

# Desactivar GPU (opcional)
Exec="/opt/Mullvad VPN/mullvad-vpn" --enable-features=UseOzonePlatform,WaylandWindowDecorations --ozone-platform=wayland %U

VSCodium en Wayland

Ir a /usr/share/applications/codium.desktop Y cambiar todas las líneas que tengan Exec con –enable-features=UseOzonePlatform,WaylandWindowDecorations –ozone-platform=wayland. Por ejemplo:

Exec=/usr/share/codium/codium --enable-features=UseOzonePlatform,WaylandWindowDecorations --ozone-platform=wayland --new-window %F

Eww


Instalación

sudo dnf install gtk3-devel gtk-layer-shell-devel libdbusmenu-gtk3-devel pango-devel gdk-pixbuf2-devel cairo-devel glib2-devel
cargo install --locked --no-default-features --features=wayland --git https://github.com/elkowar/eww eww
sudo dnf remove gtk3-devel gtk-layer-shell-devel libdbusmenu-gtk3-devel pango-devel gdk-pixbuf2-devel cairo-devel glib2-devel

Ironbar


Me rendí antes de terminarla

Instalación en Fedora

sudo dnf install gtk3-devel gtk-layer-shell-devel openssl-devel libdbusmenu-gtk3-devel pulseaudio-libs-devel libinput-devel luajit-devel lua-lgi libevdev-devel
cargo install --locked --git https://github.com/jakestanger/ironbar.git ironbar
sudo dnf remove gtk3-devel gtk-layer-shell-devel openssl-devel libdbusmenu-gtk3-devel pulseaudio-libs-devel libinput-devel luajit-devel lua-lgi libevdev-devel

Labwc


sudo dnf install labwc

En ~/.config/labwc copia el rc.xml

Alacritty


Crates.io

Aquí

sudo dnf install cmake freetype-devel fontconfig-devel libxcb-devel libxkbcommon-devel g++
cargo install alacritty

Extra

El .desktop

git clone https://github.com/alacritty/alacritty/
cd alacritty
sudo desktop-file-install extra/linux/Alacritty.desktop

Tuigreet en Fedora


sudo dnf install greetd tuigreet

En /etc/greetd/config.toml

[terminal]
vt = 1

[default_session]
command = "tuigreet --cmd 'niri --session' --time --remember --asterisks"
user = "greetd"

Luego:

sudo systemctl set-default graphical.target
sudo systemctl enable greetd
sudo systemctl start greetd

Autologin en TTY1


sudo EDITOR=hx systemctl edit getty@tty1

Agregar este bloque:

[Service]
ExecStart=
ExecStart=-/usr/bin/agetty --autologin <user> --noclear %I $TERM
sudo systemctl daemon-reload
sudo systemctl restart getty@tty1.service

Forzar modo oscuro en el navegador


  1. Abre el Administrador de marcadores del navegador (por ejemplo Ctrl+Shift+O o Ctrl+Shift+B).
  2. Haz clic en Agregar marcador.
  3. En Nombre pon “Dark Mode” (o el que prefieras).
  4. En URL pega:
javascript:(function(){var s=document.getElementById('darkmode-toggle');s?s.remove():(s=document.createElement('style'),s.id='darkmode-toggle',s.textContent="html{filter:invert(1)hue-rotate(180deg)!important;}img,video,iframe{filter:invert(1)hue-rotate(180deg)!important;}",document.head.appendChild(s));})();
  1. Guarda el marcador.
  2. (Opcional) Habilita la barra de marcadores para acceder rápido.
  3. Haz clic en el bookmarklet “Dark Mode” en cualquier página para invertir colores.

SHA


Trucos de sha256sum

Hacer sha256sum a todos los archivos dentro de un directorio y sus subdirectorios.

find path/to/directory -type f -exec sha256sum {} + > hashes.sha256
  • -type f: significa tipo archivo.
  • {}: representa el nombre del archivo actual en find.
  • +: indica el final del comando que se ejecuta con -exec. Cuando se usa find, agrupa los nombres de archivo y ejecuta el comando una sola vez con una lista de archivos, lo que es más eficiente que usar ;.

doas


Ejemplo en Fedora

sudo su
dnf install -y doas # pacman también funciona y la mayoría de gestores sirven
echo "permit persist setenv {PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin} :wheel" > /etc/doas.conf
chown -c root:root /etc/doas.conf
chmod -c 0400 /etc/doas.conf

SSH


Conexión simple entre Linux

Hacer esto en el servidor de destino

sudo dnf install -y sshd # openssh-server, creo
sudo systemctl start sshd # habilitar para que quede activo
ip addr show # Buscar la IP local
ssh user@192.168.x.x # IP local

Copiar archivos

scp /path/to/my/file user@192.168.x.x:/path/in/destiny/desire # usuario@ip_local:ruta/destino

GPG


Cifrar

Empaquetar una carpeta (no comprimir, más rápido)

tar -cvf carpeta.tar carpeta_a_encriptar

Cifrar carpeta

gpg -c carpeta.tar

Limpiar

rm -rf carpeta_a_encriptar

Descifrar

Descifrar el GPG

gpg carpeta.tar.gpg

Desempaquetar

tar -xvf carpeta.tar

LUKS


Creando una partición:

sudo fdisk /dev/sdb
n
# Presiona Enter en todo
w

Encriptando la partición creada:

sudo cryptsetup luksFormat /dev/sdb1
sudo cryptsetup open /dev/sdb1 a
sudo mkfs.ext4 /dev/mapper/a
sudo cryptsetup close a
sync

USBGuard


sudo dnf install usbguard usbguard-selinux
sudo systemctl enable --now usbguard
sudo bash -c "usbguard generate-policy > /etc/usbguard/rules.conf"

Manejar dispositivos temporalmente

sudo usbguard list-devices
sudo usbguard allow-device #ID/Numero
sudo usbguard block-device #ID/Numero

Permitir dispositivos permanentemente

Primera vez

usbguard generate-policy > rules.conf
hx rules.conf
sudo install -m 0600 -o root -g root rules.conf /etc/usbguard/rules.conf
sudo systemctl restart usbguard

Cambio normal

Agregar toda la ruta que aparece en usbguard list-devices, sin el primer número y poniendo allow.

sudo hx /etc/usbguard/rules.conf
sudo systemctl restart usbguard

Firewalld


Entendiendo Firewalld: Tu Guardián en Linux

Firewalld es el demonio de firewall por defecto en distribuciones como Fedora, AlmaLinux, CentOS y RHEL. A diferencia de su predecesor, iptables (que también está por debajo, pero firewalld es una capa de abstracción superior), firewalld utiliza un concepto de zonas para gestionar las reglas de firewall, lo que lo hace más fácil de usar y más dinámico.


El Concepto de Zonas en Firewalld

Imagina tu red dividida en diferentes áreas de “confianza”. Cada una de estas áreas es una zona, y a cada zona se le asigna un nivel de confianza y un conjunto de reglas que definen qué tipo de tráfico se permite o se bloquea. Las interfaces de red (Ethernet, Wi-Fi) o las direcciones IP de origen se asignan a estas zonas.

Cuando un paquete de red llega a tu sistema, firewalld intenta asignarlo a una zona. Una vez que el paquete está en una zona, se aplican las reglas de esa zona para decidir si se permite, se rechaza o se descarta.

Zonas Predefinidas Comunes:

Firewalld viene con varias zonas predefinidas, cada una con un nivel de confianza y reglas por defecto:

  • public: La zona por defecto para redes públicas. No confías en otros ordenadores en la red. Solo se aceptan las conexiones entrantes explícitamente permitidas. Es un buen punto de partida para servidores.
  • home: Para redes domésticas. Confías la mayoría de los otros ordenadores en la red.
  • work: Para redes de trabajo. Confías la mayoría de los otros ordenadores.
  • internal: Para redes internas. Mayor nivel de confianza que home o work.
  • trusted: La zona de mayor confianza. Todas las conexiones de red son aceptadas. ¡Úsala con precaución!
  • dmz (Demilitarized Zone): Para servidores que son públicos pero con acceso limitado a tu red interna.
  • drop: Cualquier paquete entrante es descartado sin ninguna respuesta. Solo son posibles las conexiones salientes. Es la más restrictiva.
  • block: Rechaza cualquier paquete entrante con un mensaje de “host prohibido”.
  • external: Usada para redes externas, a menudo con enmascaramiento (NAT) habilitado, típico de routers.

Las interfaces de red se asignan a una zona. Por defecto, tu interfaz de red principal a menudo se asigna a la zona public.


Funcionamiento Básico de firewalld

  • firewall-cmd: Esta es la herramienta de línea de comandos principal para interactuar con firewalld.
  • --permanent: Las reglas que añades se pueden aplicar de forma temporal (solo hasta el siguiente reinicio o recarga del firewall) o de forma permanente. Para que una regla persista después de un reinicio, debes usar la opción --permanent.
  • --reload: Después de añadir o quitar reglas con --permanent, necesitas recargar el firewall para que los cambios permanentes se apliquen al firewall en ejecución. Si no usas --permanent, las reglas se aplican inmediatamente pero se pierden.

Comandos Clave de firewalld

1. Ver Reglas Actuales

Para ver las reglas activas en una zona específica (o en la zona por defecto si no especificas una):

sudo firewall-cmd --list-all --zone=public
  • Esto mostrará el estado de la zona public: servicios permitidos, puertos abiertos, reglas ricas, etc.
  • Si no especificas --zone=public, mostrará las reglas de la zona por defecto (que a menudo es public).

Para ver todas las zonas y sus configuraciones:

sudo firewall-cmd --list-all-zones

Para ver qué interfaces están asignadas a qué zonas:

sudo firewall-cmd --get-active-zones

2. Añadir Reglas (Permitir Tráfico)

Para permitir tráfico entrante a un puerto específico en una zona:

sudo firewall-cmd --permanent --add-port=PUERTO/protocolo --zone=zona_deseada
sudo firewall-cmd --reload
  • PUERTO: El número del puerto (ej., 18089).
  • protocolo: tcp o udp.
  • zona_deseada: La zona donde quieres aplicar la regla (ej., public).
  • Ejemplo para Monero RPC: sudo firewall-cmd --permanent --add-port=18089/tcp --zone=public

Para permitir tráfico entrante para un servicio conocido (SSH, HTTP, HTTPS, etc.) en una zona:

sudo firewall-cmd --permanent --add-service=nombre_servicio --zone=zona_deseada
sudo firewall-cmd --reload
  • nombre_servicio: El nombre del servicio (ej., ssh, http). Firewalld tiene definiciones preestablecidas para los puertos y protocolos de muchos servicios comunes.

Para permitir tráfico de una fuente específica (dirección IP o rango) a una zona (esto es más restrictivo y seguro):

sudo firewall-cmd --permanent --add-source=IP_o_rango_CIDR --zone=zona_deseada
sudo firewall-cmd --reload
  • IP_o_rango_CIDR: Por ejemplo, 192.168.1.0/24 para toda tu subred local.
  • Ejemplo para Monero con fuente específica:
    sudo firewall-cmd --permanent --add-source=192.168.1.0/24 --add-port=18089/tcp --zone=public
    sudo firewall-cmd --reload
    
    (Reemplaza 192.168.1.0/24 con el rango de tu red local si es diferente).

3. Eliminar Reglas

Para quitar una regla de puerto:

sudo firewall-cmd --permanent --remove-port=PUERTO/protocolo --zone=zona_deseada
sudo firewall-cmd --reload

Para quitar una regla de servicio:

sudo firewall-cmd --permanent --remove-service=nombre_servicio --zone=zona_deseada
sudo firewall-cmd --reload

Para quitar una regla de fuente:

sudo firewall-cmd --permanent --remove-source=IP_o_rango_CIDR --zone=zona_deseada
sudo firewall-cmd --reload

4. Recargar el Firewall

Siempre que hagas cambios permanentes, ¡no olvides recargar!

sudo firewall-cmd --reload

Esto aplica los cambios permanentes al firewall en ejecución sin interrumpir las conexiones existentes.


¿Qué significa --zone=public?

Cuando usas --zone=public, estás indicando que la regla que estás añadiendo o modificando debe aplicarse a la zona public.

En el contexto de tu VM de AlmaLinux:

  • Si la interfaz de red de tu VM está asignada a la zona public (que es lo más común por defecto, especialmente si la VM está en modo puente y no hay otras zonas configuradas explícitamente), entonces al añadir una regla a la zona public, estás permitiendo que el tráfico del puerto 18089/tcp llegue a esa VM desde tu red local (o cualquier red asociada a la zona public).
  • La zona public se considera “no confiable” por defecto, lo que significa que a menos que una conexión esté explícitamente permitida, será bloqueada. Al añadir el puerto 18089 a esta zona, estás haciendo esa excepción específica.

Mullvad VPN CLI


Más usados

ComandoDescripción
mullvad account loginInicia sesión en tu cuenta Mullvad.
mullvad account getMuestra la info de tu cuenta, incluyendo número, dispositivo y fecha de expiración.
mullvad relay listLista ubicaciones de servidores disponibles.
mullvad relay set location <country_code> <city_code>Selecciona una ubicación. Reemplaza <country_code> y <city_code> con los valores deseados.
mullvad relay set location <server_name>Selecciona un servidor específico por nombre.
mullvad connectConecta a la ubicación seleccionada.
mullvad disconnectDesconecta la VPN.
mullvad status -vRevisa el estado de conexión con detalles.
mullvad auto-connect set onHabilita auto-conexión al inicio.
mullvad lockdown-mode set onHabilita Lockdown para bloquear todo el tráfico hasta conectar con Mullvad.
mullvad dns set default --block-ads --block-trackers --block-malware --block-adult-contentPara activar todos los filtros DNS excepto redes sociales, usa este comando.
mullvad relay set tunnel-protocol wireguardUsa WireGuard como protocolo de túnel (por defecto).
mullvad tunnel set wireguard --quantum-resistant onHabilita Quantum Resistant.

Comandos básicos

ComandoDescripción
mullvad account login <account_number>Inicia sesión en tu cuenta Mullvad. Reemplaza <account_number> por tu número real.
mullvad account getMuestra la info de tu cuenta, incluyendo número, dispositivo y fecha de expiración.
mullvad account list-devicesLista los dispositivos asociados a tu cuenta.
mullvad relay listLista ubicaciones de servidores disponibles.
mullvad relay set location <country_code> <city_code>Selecciona una ubicación. Reemplaza <country_code> y <city_code> con los valores deseados.
mullvad relay set location <server_name>Selecciona un servidor específico por nombre.
mullvad connectConecta a la ubicación seleccionada.
mullvad disconnectDesconecta la VPN.
mullvad relay updateFuerza actualización de la lista de servidores.
mullvad status -vRevisa el estado de conexión con detalles.

Comandos avanzados

ComandoDescripción
mullvad relay set tunnel-protocol openvpnUsa OpenVPN como protocolo de túnel.
mullvad relay set tunnel openvpn --transport-protocol tcpUsa OpenVPN sobre TCP.
mullvad relay set tunnel-protocol wireguardUsa WireGuard como protocolo de túnel (por defecto).
mullvad auto-connect set onHabilita auto-conexión al inicio.
mullvad auto-connect set offDeshabilita auto-conexión al inicio.
mullvad lan set allowHabilita acceso LAN.
mullvad lockdown-mode set onHabilita Lockdown para bloquear todo el tráfico hasta conectar con Mullvad.
mullvad tunnel set ipv6 onHabilita IPv6 dentro del túnel.

Split tunneling (Linux)

ComandoDescripción
mullvad-exclude <program>Inicia un proceso excluido de Mullvad.
mullvad split-tunnel add <pid>Excluye un proceso en ejecución usando su PID.
mullvad split-tunnel listLista procesos excluidos.
mullvad split-tunnel delete <pid>Para restaurar un proceso excluido usa este comando.
mullvad split-tunnel clearPara restaurar todos los procesos excluidos usa este comando.

Comandos de Shadowsocks

ComandoDescripción
mullvad bridge set location <location>Define ubicación para Shadowsocks. Reemplaza <location> con país o ciudad.
mullvad bridge set state onHabilita modo puente para Shadowsocks.
mullvad bridge set state offDeshabilita modo puente.
mullvad bridge set custom set shadowsocks --cipher <CIPHER> <REMOTE_IP> <REMOTE_PORT> <PASSWORD>Configura ajustes avanzados de Shadowsocks.

Comandos DNS

ComandoDescripción
mullvad dns set default --helpPara ver la ayuda usa este comando.
mullvad dns set default --block-ads --block-trackers --block-malware --block-gambling --block-adult-contentPara activar todos los filtros DNS excepto redes sociales, usa este comando.
mullvad dns set defaultPara desactivar todos los bloqueadores usa este comando.

Listas personalizadas

ComandoDescripción
mullvad custom-list new FavoritesPara crear una lista personalizada llamada “Favorites” usa este comando.
mullvad custom-list edit add Favorites se-mma-wg-001Para agregar un servidor, ciudad o país a la lista usa uno de estos comandos.
mullvad custom-list edit add Favorites se gotPara agregar un servidor, ciudad o país a la lista usa uno de estos comandos.
mullvad custom-list edit add Favorites sePara agregar un servidor, ciudad o país a la lista usa uno de estos comandos.
mullvad relay set custom-list FavoritesPara seleccionar tu lista personalizada y conectarte, usa este comando.
mullvad custom-list edit remove Favorites se-mma-wg-001Para eliminar un servidor, ciudad o país de la lista usa uno de estos comandos (igual que agregar).
mullvad custom-list edit rename Favorites FavouritesPara renombrar una lista personalizada usa este comando.
mullvad custom-list listPara listar todas tus listas personalizadas y su contenido usa este comando.

Restablecer ajustes

ComandoDescripción
mullvad factory-resetEste comando restablece ajustes de fábrica, borra logs y cache, desconecta la app y cierra sesión.

Página oficial

Mullvad CLI

WebRTC

Sitio de Mullvad


Firefox

Nota: Firefox es el único navegador que puede desactivar WebRTC por completo.

    1. Escribe about:config en la barra de direcciones y presiona Enter.
    1. Haz clic en I accept the risk!.
    1. Escribe media.peerconnection.enabled en el buscador. Debe aparecer una sola entrada.
    1. Haz doble clic en la entrada para cambiarla a false.

Para habilitar WebRTC nuevamente, vuelve a cambiarlo a “true”.

Brave (desktop y Android)

Desktop

Abre Ajustes y haz clic en el icono de la lupa arriba a la derecha y busca webrtc. En WebRTC IP Handling Policy selecciona Disable Non-Proxied UDP.

Android

Abre Ajustes y toca Brave Shields & privacy. Luego baja y toca WebRTC IP Handling Policy. Selecciona Disable Non-Proxied UDP y toca la X arriba a la derecha.

Pruebas

Mullvad SOCKS5


Brave

Agrega esta línea –proxy-server=socks5://10.64.0.1 en el .desktop (en /home/user/.local/share/applications para que no se sobrescriba)

Exec=/usr/bin/brave-browser-stable --proxy-server=socks5://10.64.0.1 --enable-features=UseOzonePlatform --ozone-platform=wayland %U

ssss


ssss-split -t 3 -n 5
Generating shares using a (3,5) scheme with dynamic security level.
Enter the secret, at most 128 ASCII characters: my secret root password
Using a 184 bit security level.
1-1c41ef496eccfbeba439714085df8437236298da8dd824
2-fbc74a03a50e14ab406c225afb5f45c40ae11976d2b665
3-fa1c3a9c6df8af0779c36de6c33f6e36e989d0e0b91309
4-468de7d6eb36674c9cf008c8e8fc8c566537ad6301eb9e
5-4756974923c0dce0a55f4774d09ca7a4865f64f56a4ee0
ssss-combine -t 3
Enter 3 shares separated by newlines:
Share [1/3]: 3-fa1c3a9c6df8af0779c36de6c33f6e36e989d0e0b91309
Share [2/3]: 5-4756974923c0dce0a55f4774d09ca7a4865f64f56a4ee0
Share [3/3]: 2-fbc74a03a50e14ab406c225afb5f45c40ae11976d2b665
Resulting secret: my secret root password

Qrrs


Qrrs

Uso

Generar QR rápido

qrrs "Your input here"
qrrs "Your input here" --invert_colors

Generar QR y luego leerlo

qrrs "Something" /tmp/qr.png
$ qrrs --read /tmp/qr.png
Something

Imprimir el código generado en la terminal

qrrs -t "Something" /tmp/qr.png

█████████████████████████████
█████████████████████████████
████ ▄▄▄▄▄ █▄ █▄▄█ ▄▄▄▄▄ ████
████ █   █ █▀▄████ █   █ ████
████ █▄▄▄█ █ ▄█▀▄█ █▄▄▄█ ████
████▄▄▄▄▄▄▄█ ▀ ▀ █▄▄▄▄▄▄▄████
████▄███ █▄▄ ▄▀ ▀▄▄▄  █▀▄████
████▄ ▀█▀▄▄▀▄▀▀▄█▀▄█ █▄ ▀████
████▄█▄██▄▄▄▀▀▀█ ▄▀█ ▀█▄ ████
████ ▄▄▄▄▄ █▄▀▄▀ ▄▄▀ ██ █████
████ █   █ █▄█▀ ▀▄▄█ ▀▀ ▀████
████ █▄▄▄█ ██▀ ▄█▀ ▀ ████████
████▄▄▄▄▄▄▄█▄▄▄█▄▄▄▄█▄██▄████
█████████████████████████████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀

Mostrar el código como texto en la terminal

qrrs --read --terminal /tmp/qr.png

█████████████████████████████
█████████████████████████████
████ ▄▄▄▄▄ █▄ █▄▄█ ▄▄▄▄▄ ████
████ █   █ █▀▄████ █   █ ████
████ █▄▄▄█ █ ▄█▀▄█ █▄▄▄█ ████
████▄▄▄▄▄▄▄█ ▀ ▀ █▄▄▄▄▄▄▄████
████▄███ █▄▄ ▄▀ ▀▄▄▄  █▀▄████
████▄ ▀█▀▄▄▀▄▀▀▄█▀▄█ █▄ ▀████
████▄█▄██▄▄▄▀▀▀█ ▄▀█ ▀█▄ ████
████ ▄▄▄▄▄ █▄▀▄▀ ▄▄▀ ██ █████
████ █   █ █▄█▀ ▀▄▄█ ▀▀ ▀████
████ █▄▄▄█ ██▀ ▄█▀ ▀ ████████
████▄▄▄▄▄▄▄█▄▄▄█▄▄▄▄█▄██▄████
█████████████████████████████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀

Guardarlo en otro archivo

qrrs --read --terminal /tmp/qr.png /tmp/qr1.png

Casi el mismo resultado, pero sin la opción de terminal. En vez de imprimir el QR en la terminal, verás el texto.

qrrs --read /tmp/qr.png /tmp/qr1.png

Contraseña GRUB2


En Libreboot

    1. Generar el hash de la contraseña
grub2-mkpasswd-pbkdf2

La salida debería ser algo como:

grub.pbkdf2.sha512.10000.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    1. Abrir con sudo /etc/grub.d/40_custom. Al final agrega:
#──────────────────────────────────────
set superusers="admin"
password_pbkdf2 admin grub.pbkdf2.sha512.10000.XXXXXXXXXXXXXXXXXXXXXXXX
#──────────────────────────────────────
    1. Actualizar GRUB
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
sudo reboot
    1. Probar Probar con “e”, debería pedir un usuario y una contraseña.

Guía de Impresión Minimalista Fedora

1. Instalación de paquetes necesarios

Instala el motor de impresión, el cliente y el driver específico (en este caso para impresoras láser Brother):

sudo dnf install cups cups-client printer-driver-brlaser

2. Activación del servicio (Modo Eficiente)

Activa solo el socket de systemd. El servicio principal de CUPS solo se encenderá cuando mandes un archivo a imprimir, ahorrando recursos:

sudo systemctl disable cups
sudo systemctl enable --now cups.socket

3. Configuración inicial

  1. Accede a la interfaz local: http://localhost:631
  2. Ve a Administration > Add Printer (usa tu usuario y contraseña de sistema).
  3. Selecciona la impresora detectada por USB o red.
  4. Elige el fabricante y el modelo correspondiente en la lista (usando el driver brlaser si es compatible).
  5. En Set Default Options, selecciona el tamaño de papel (ej. A4) y guarda.

4. Definir impresora predeterminada (CLI)

Para que el sistema sepa a dónde enviar los archivos por defecto sin errores:

# Listar nombre exacto asignado a la impresora
lpstat -p

# Establecer como predeterminada (reemplaza con tu nombre)
lpadmin -d [NOMBRE_IMPRESORA]

5. Comandos rápidos de uso

  • Imprimir cualquier archivo:
    lp archivo.pdf
    
  • Imprimir imagen ajustada a la página:
    lp -o fit-to-page imagen.png
    
  • Ver estado de la cola:
    lpq
    
  • Limpiar todos los trabajos pendientes:
    cancel -a
    

Cómo instalar temas GRUB en Fedora (Libreboot)


Instalar un tema

1. Descargar el tema:

cd /tmp
git clone https://github.com/usuario/nombre-tema.git

2. Copiar a la carpeta de temas de GRUB:

sudo mkdir -p /boot/grub2/themes
sudo cp -r /tmp/nombre-tema/carpeta-del-tema /boot/grub2/themes/mi-tema

Verifica que dentro exista theme.txt:

ls /boot/grub2/themes/mi-tema/theme.txt

3. Editar configuración de GRUB:

sudo hx /etc/default/grub

Añade o modifica:

GRUB_THEME="/boot/grub2/themes/mi-tema/theme.txt"

Si existe GRUB_TERMINAL=console, coméntala (los temas necesitan modo gráfico):

#GRUB_TERMINAL=console

4. Regenerar grub.cfg:

sudo grub2-mkconfig -o /boot/grub2/grub.cfg

5. Reiniciar:

sudo reboot

Desinstalar / volver al menú normal

Edita /etc/default/grub y quita la línea GRUB_THEME. Regenera:

sudo grub2-mkconfig -o /boot/grub2/grub.cfg

Cambiar de tema

Repite los pasos 1-5 con el nuevo tema. Solo puede haber un GRUB_THEME activo a la vez.


Dónde encontrar temas


Notas

  • Un tema GRUB es solo imágenes (PNG), fuentes (.pf2) y un archivo de texto (theme.txt). No ejecuta código. Es seguro.
  • Si el tema se ve mal, puede ser incompatibilidad de resolución. Busca temas que coincidan con tu pantalla (1920x1080 = 16:9).
  • Esto funciona porque Libreboot carga el grub.cfg de Fedora, que incluye la directiva del tema.

Guía de Dual-Boot en Libreboot

Guía práctica para configurar dual-boot (o multi-boot) de distribuciones Linux en un sistema con Libreboot. Basada en Libreboot 26.01 “Magnanimous Max” con GRUB 2.14.


Conceptos clave

En Libreboot, GRUB vive en la ROM (chip SPI), no en el disco. Cuando instalas una distro y ejecuta grub-install, ese GRUB en disco nunca se ejecuta como bootloader. Libreboot solo lee el archivo grub.cfg de cada distro mediante el comando configfile.

El flujo de arranque es: coreboot → GRUB (desde ROM) → escanea discos → encuentra grub.cfg → carga kernel.

No existe chainloading (chainloader +1 no funciona). No necesitas ESP (EFI System Partition). El GRUB de la ROM ya trae los módulos necesarios compilados (ext2, btrfs, luks2, search, configfile, etc.), por lo que no necesitas insmod.

Nombres de dispositivo en GRUB de Libreboot

Los discos NVMe se ven como (nvme0n1,gptX). Los SATA como (ahci0,gptX). USB como (usb0). Puedes verificarlos presionando c en el menú de Libreboot y escribiendo ls.


Esquema mínimo de particiones

Cada distro necesita como mínimo:

/dev/nvme0n1pX — ext4       — /boot de la distro (~1 GiB)
/dev/nvme0n1pY — crypto_LUKS — / de la distro (resto)

Ejemplo con Fedora + Linux Mint:

nvme0n1p1 — (reservada/vacía)
nvme0n1p2 — ext4        — /boot Fedora
nvme0n1p3 — LUKS2       — / Fedora (cifrado)
nvme0n1p4 — ext4        — /boot Distro 2
nvme0n1p5 — LUKS2       — / Distro 2 (cifrado)

Para agregar una tercera distro, simplemente añades dos particiones más (boot + LUKS).

Reglas importantes:

  • Cada distro debe tener su propio /boot separado (ext4).
  • Cada distro puede tener su propia partición LUKS independiente.
  • No se necesita ESP ni partición EFI.
  • Al instalar, deja que el instalador instale GRUB normalmente. Aunque no se usa como bootloader, el proceso genera el grub.cfg que Libreboot necesita.

Cómo agregar una distro al menú de arranque

Paso 1: Instalar la distro

Usa particionado manual en el instalador. Asigna su /boot y su partición raíz (con LUKS si quieres cifrado). No toques las particiones de las distros existentes.

Paso 2: Verificar que generó grub.cfg

Desde tu distro principal:

sudo mkdir -p /mnt/newboot
sudo mount /dev/nvme0n1pX /mnt/newboot    # X = partición /boot de la nueva distro
ls /mnt/newboot/grub/grub.cfg             # Debian/Ubuntu/Mint usan /grub/
ls /mnt/newboot/grub2/grub.cfg            # Fedora usa /grub2/
sudo umount /mnt/newboot

Si no existe grub.cfg, hay que generarlo vía chroot (ver sección “Solución de problemas”).

Paso 3: Obtener el UUID del /boot de la nueva distro

lsblk -f

Busca el UUID de la partición ext4 que es /boot de la nueva distro.

Paso 4: Agregar entrada en 40_custom de la distro principal

Edita el archivo de entradas personalizadas de GRUB en tu distro principal (la que Libreboot carga por defecto):

sudo hx /etc/grub.d/40_custom

El archivo debe verse así:

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.

menuentry 'Nombre de la Distro' --class nombredistro --class gnu-linux --class os {
    search --no-floppy --fs-uuid --set=root UUID_DEL_BOOT
    configfile /grub/grub.cfg
}

Reemplaza:

  • Nombre de la Distro → lo que quieras ver en el menú.
  • --class → el icono que se usara
  • UUID_DEL_BOOT → el UUID de la partición /boot de esa distro (paso 3).
  • /grub/grub.cfg → usa /grub2/grub.cfg si es Fedora.

Para múltiples distros, simplemente añade más bloques menuentry:

#!/bin/sh
exec tail -n +3 $0

menuentry 'Linux Mint' {
    search --no-floppy --fs-uuid --set=root aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
    configfile /grub/grub.cfg
}

menuentry 'Debian GNU/Linux' {
    search --no-floppy --fs-uuid --set=root ffffffff-1111-2222-3333-444444444444
    configfile /grub/grub.cfg
}

menuentry 'Arch Linux' {
    search --no-floppy --fs-uuid --set=root 55555555-6666-7777-8888-999999999999
    configfile /grub/grub.cfg
}

Paso 5: Asegurar que es ejecutable y regenerar

sudo chmod +x /etc/grub.d/40_custom

En Fedora:

sudo grub2-mkconfig -o /boot/grub2/grub.cfg

En Debian/Ubuntu/Mint:

sudo update-grub

Paso 6: Reiniciar y probar

sudo reboot

La nueva distro aparecerá al final del menú de arranque.


Arranque manual desde consola GRUB

Si algo falla, presiona c en el menú de Libreboot para obtener la consola GRUB.

Ver dispositivos disponibles

ls

Arrancar manualmente cargando grub.cfg de una distro

search --no-floppy --fs-uuid --set=root UUID_DEL_BOOT
configfile /grub/grub.cfg

Arrancar manualmente sin grub.cfg

set root=(nvme0n1,gptX)
linux /vmlinuz-VERSION root=/dev/mapper/NOMBRE_LUKS
initrd /initrd.img-VERSION
boot

Solución de problemas

La distro no generó grub.cfg

Desde tu distro principal, hacer chroot:

# Abrir LUKS si es cifrado
sudo cryptsetup open /dev/nvme0n1pY nombre-root

# Montar raíz (ajustar opciones según filesystem)
sudo mkdir -p /mnt/distro
sudo mount /dev/mapper/nombre-root /mnt/distro
# Si es btrfs con subvolumen:
# sudo mount -o subvol=@rootfs /dev/mapper/nombre-root /mnt/distro

# Montar /boot
sudo mount /dev/nvme0n1pX /mnt/distro/boot

# Montar sistemas virtuales
sudo mount --bind /dev /mnt/distro/dev
sudo mount --bind /dev/pts /mnt/distro/dev/pts
sudo mount --bind /proc /mnt/distro/proc
sudo mount --bind /sys /mnt/distro/sys

# Chroot y generar grub.cfg
sudo chroot /mnt/distro
update-grub          # Debian/Ubuntu/Mint
# grub2-mkconfig -o /boot/grub2/grub.cfg   # Fedora

exit

# Limpiar
sudo umount /mnt/distro/sys
sudo umount /mnt/distro/proc
sudo umount /mnt/distro/dev/pts
sudo umount /mnt/distro/dev
sudo umount /mnt/distro/boot
sudo umount /mnt/distro
sudo cryptsetup close nombre-root

Cae a initramfs (BusyBox) al arrancar

El initramfs no tiene instrucciones para desbloquear LUKS. Verificar crypttab y regenerar initramfs vía chroot:

# Dentro del chroot:
cat /etc/crypttab    # Debe tener una entrada para el volumen LUKS
update-initramfs -u -k all   # Debian/Ubuntu/Mint
# dracut --regenerate-all     # Fedora

Notas sobre distros específicas

  • Fedora: usa /grub2/grub.cfg (no /grub/). Usa BLS por defecto. Si da problemas, editar /etc/default/grub y poner GRUB_ENABLE_BLSCFG=false, luego regenerar. Configurar GRUB_TERMINAL=console.
  • Debian/Ubuntu/Mint: usa /grub/grub.cfg. Formato tradicional, compatible sin ajustes.
  • Arch Linux: usa /grub/grub.cfg. Compatible sin ajustes.

Notas sobre encriptación LUKS

  • Libreboot 26.01+ soporta LUKS2 con argon2id nativamente (GRUB 2.14).
  • El desbloqueo en GRUB es más lento que en el kernel (sin aceleración hardware). Si tarda mucho, ajustar parámetros KDF con: cryptsetup luksConvertKey /dev/sdX --pbkdf argon2id --pbkdf-force-iterations 4 --pbkdf-memory 131072
  • Si /boot está fuera del LUKS (como en esta guía), GRUB no necesita descifrar nada — el initramfs se encarga.

Referencia rápida

AcciónComando
Ver UUIDslsblk -f
Editar entradas customsudo hx /etc/grub.d/40_custom
Regenerar GRUB (Fedora)sudo grub2-mkconfig -o /boot/grub2/grub.cfg
Regenerar GRUB (Debian/Mint)sudo update-grub
Consola GRUB en LibrebootPresionar c en el menú
Ver dispositivos en GRUBls
Regenerar initramfs (Debian)sudo update-initramfs -u -k all
Regenerar initramfs (Fedora)sudo dracut --regenerate-all
Abrir LUKSsudo cryptsetup open /dev/nvme0n1pX nombre
Cerrar LUKSsudo cryptsetup close nombre

GNU Stow


sudo dnf install stow

Funciona así:

Home normal:

~
|
|-> .zshrc
 -> .config
    -> alacritty
       -> alacritty.toml
       -> *

Luego en Stow:

stow_dir
|
|-> zsh
|  -> .zshrc
|
 -> alacritty
    -> .config
       -> alacritty
          -> alacritty.toml
          -> *

Luego para hacer los enlaces simbólicos:

stow zsh alacritty

dd


sudo dd if=tails.img of=device bs=16M oflag=direct status=progress
sudo dd if=~/Descargas/kali-linux.iso of=/dev/sdb bs=4M status=progress oflag=sync

Búsqueda en CLI (grep, rg, find, locate, fd)


Guía rápida para buscar texto y archivos desde la terminal.

Qué usar según el caso

  • grep: buscar texto dentro de archivos.
  • rg (ripgrep): igual que grep, pero más rápido y respeta .gitignore.
  • find: buscar archivos por nombre, fecha, tamaño o permisos.
  • locate: buscar rutas rápido usando una base de datos local.
  • fd: alternativa moderna a find para búsqueda por nombre.

grep

# Buscar texto en archivos (recursivo)
grep -RIn "patron" ruta/

# Ignorar mayúsculas/minúsculas
grep -RIn -i "patron" ruta/

# Buscar y excluir líneas
grep -RIn "patron" ruta/ | grep -v "excluir"

rg (ripgrep)

# Buscar texto en el repo actual
rg "patron"

# Buscar solo en .md
rg -n -g "*.md" "patron"

# Listar archivos que contienen el patrón
rg -l "patron"

find

# Buscar archivos por extensión
find . -type f -name "*.md"

# Buscar archivos modificados en los últimos 7 días
find . -type f -mtime -7

# Buscar texto usando find + grep
find . -type f -name "*.conf" -exec grep -n "patron" {} +

locate

# Buscar rutas en la base de datos
locate nombre_archivo

# Actualizar la base (según distro)
sudo updatedb

fd

# Buscar por nombre (regex)
fd "config" ~/.config

# Filtrar por extension
fd -e rs

# Incluir ocultos y no respetar .gitignore
fd -H -I "patron" .

Tips rápidos

  • Si buscas texto: rg o grep.
  • Si buscas archivos por nombre: fd (simple) o find (filtros avanzados).
  • Si quieres máxima velocidad para rutas conocidas: locate.

Yazi


Requisitos

Para usar Yazi necesitas lo siguiente:

  • file (detección de tipo de archivo)

Opcional

Puedes ampliar Yazi con herramientas de línea de comandos:

  • nerd-fonts (recomendado)
  • ffmpeg (miniaturas de video)
  • 7-Zip (extracción y vista previa de archivos)
  • jq (vista previa de JSON)
  • poppler (vista previa de PDF)
  • fd (búsqueda de archivos)
  • rg (búsqueda dentro de archivos)
  • fzf (navegación rápida por subárboles, >= 0.53.0)
  • zoxide (navegación por historial, requiere fzf)
  • resvg (vista previa de SVG)
  • ImageMagick (vista previa de fuentes, HEIC y JPEG XL)
  • xclip / wl-clipboard / xsel (portapapeles en Linux)

Compilar

sudo dnf install chafa fzf
cargo install --locked yazi-fm yazi-cli

Uso

yazi

O crea una función en bash para que respete el cwd:

y() {
  local tmp
  tmp="$(mktemp -t "yazi-cwd.XXXXXX")"
  yazi "$@" --cwd-file="$tmp"
  if [ -s "$tmp" ]; then
    local cwd
    cwd="$(cat "$tmp")"
    [ -n "$cwd" ] && [ "$cwd" != "$PWD" ] && cd "$cwd"
  fi
  rm -f "$tmp"
}

Luego ejecuta:

yazi

Atajos de teclado

F1 para ver keybindings

Recursos oficiales

Yazi GitHub

Página de Yazi


Crates.io

ln


  • ln (hard link)

    • Crea un segundo nombre (alias) para el mismo archivo en el sistema de ficheros.

    • Ambos nombres comparten el mismo inode y, por tanto, los mismos datos; borrar uno no afecta al otro hasta que ambos se eliminen.

    • Sintaxis básica:

      ln <ruta_origen> <ruta_destino>
      
    • Limitaciones:

      • Debe residir en la misma partición.
      • Git lo trata como un archivo normal (bueno), pero no detecta que hay “vínculo” (todo bien).
  • ln -s (symbolic link / symlink)

    • Crea un pequeño archivo que apunta a otro por su ruta. No comparten inode.

    • Borrar el objetivo deja un “enlace roto”.

    • Sintaxis básica:

      ln -s <ruta_origen> <ruta_destino>
      
    • Ventajas:

      • Funciona entre distintas particiones o sistemas de ficheros.
      • Con rutas relativas, es portátil si se conserva la estructura de carpetas.
    • Consideraciones con Git:

      • Git almacena la ruta del symlink, no el contenido.
      • Quienes clonen el repo obtendrán el enlace, que puede fallar si no existe la misma ruta en sus máquinas.

Resumen de usos

  • Usa hard link (ln) cuando quieras un segundo nombre indistinguible para el mismo fichero y estés en la misma partición.
  • Usa symlink (ln -s) cuando necesites apuntar a archivos en otra ubicación o mantener portabilidad con rutas relativas.

Ghostscript (Reducir tamaño de PDF)


Para reducir el tamaño de un PDF.

sudo dnf install ghostscript
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dNOPAUSE -dQUIET -dBATCH -dDetectDuplicateImages=true -dCompressFonts=true -dSubsetFonts=true -dAutoRotatePages=/None -dPDFSETTINGS=/ebook -dColorImageDownsampleType=/Bicubic -dColorImageResolution=150 -dGrayImageDownsampleType=/Bicubic -dGrayImageResolution=150 -dMonoImageDownsampleType=/Subsample -dMonoImageResolution=300 -sOutputFile=output.pdf input.pdf

Carapace



Descargar el rpm, esto es para Nushell

sha256sum carapace-bin*linux*.rpm
sudo dnf install carapace-bin*linux*.rpm
# ~/.config/nushell/env.nu
mkdir ~/.cache/carapace
carapace _carapace nushell | save --force ~/.cache/carapace/init.nu
# ~/.config/nushell/config.nu
source ~/.cache/carapace/init.nu

LocalSend


tar -xvf LocalSend-X.XX.X-linux-XXX.tar.gz
sudo mkdir -p /opt/localsend
sudo cp data/ lib/ localsend_app /opt/localsend
cp localsend.desktop .local/share/applications/localsend.desktop

Extra

sudo firewall-cmd --add-port=53317/tcp --zone=drop

Fedora + Nix


Índice

  1. Preparando Todo
  2. Usuarios (mínimo privilegio)
  3. Login: greetd + tuigreet + niri
  4. Sudo-rs
  5. Instalar Nix (multiusuario)
  6. Configurar Nix en /etc/nix/nix.conf
  7. Sistema base con DNF
  8. Flake Home Manager
  9. Notas útiles y rollbacks

Preparación

sudo dnf up -y
sudo dnf install -y helix tar git NetworkManager-wifi NetworkManager-tui iwlwifi-mvm-firmware

Usuarios (mínimo privilegio)

  • admin → con sudo
  • main / safe → sin sudo.

Crear usuarios:

sudo groupadd -f nhm
sudo useradd -m -s /bin/bash -G nhm main  && sudo passwd main
sudo useradd -m -s /bin/bash -G nhm safe  && sudo passwd safe

Login: greetd + tuigreet + niri

sudo dnf install -y niri greetd tuigreet xdg-desktop-portal xdg-desktop-portal-wlr
sudo dnf remove -y fuzzel nano bluez

Configurar /etc/greetd/config.toml:

[terminal]
vt = 1
[default_session]
command = "tuigreet --cmd 'niri --session' --time --remember --asterisks"
user = "greetd"

Habilitar:

sudo systemctl set-default graphical.target
sudo systemctl enable greetd

Sudo-rs

su
dnf -y in sudo-rs
install -d /usr/local/bin
cat >/usr/local/bin/sudo <<'EOF'
#!/bin/sh
exec /usr/bin/sudo-rs "$@"
EOF
chmod 0755 /usr/local/bin/sudo
restorecon -v /usr/local/bin/sudo || true
type -a sudo    # debe listar /usr/local/bin/sudo primero

Su-rs

su
cat >/usr/local/bin/su <<'EOF'
#!/bin/sh
exec /usr/bin/su-rs "$@"
EOF
chmod 0755 /usr/local/bin/su
restorecon -v /usr/local/bin/su || true
type -a su    # debe listar /usr/local/bin/su primero

Instalar Nix (multiusuario)

curl --proto '=https' --tlsv1.2 -sSf -L https://artifacts.nixos.org/experimental-installer | sh -s -- install
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh

Configurar Nix en /etc/nix/nix.conf

Preparar directorio:

sudo mkdir /nhm
sudo chown admin:nhm /nhm
sudo chmod 750 /nhm
cd /nhm
git clone https://codeberg.org/Kyronix/dotfiles.git
cd dotfiles
git checkout nix-fedora
sudo git config --system --add safe.directory /nhm/dotfiles

Editar como root:

experimental-features = nix-command flakes
sandbox = true
sandbox-fallback = false
trusted-users = root @wheel
keep-outputs = true
keep-derivations = true

Aplicar:

sudo systemctl restart nix-daemon

Sistema base con DNF

sudo dnf config-manager addrepo --from-repofile=https://repository.mullvad.net/rpm/stable/mullvad.repo
sudo dnf config-manager addrepo --from-repofile=https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo
sudo dnf install -y setroubleshoot nmap dnf-plugins-core power-profiles-daemon wlogout \
  libguestfs-tools usbguard-selinux @virtualization brave-browser mullvad-vpn mullvad-browser \
  lxqt-policykit clamav swayidle pulseaudio-utils foot mako

Flake Home Manager

# Genera/Actualiza flake.lock
cd /nhm/dotfiles
nix flake update

Desde el usuario correr este comando:

nix run /nhm/dotfiles#home-manager -- switch --flake /nhm/dotfiles#<usuario>
# Logeado como admin
nix run /nhm/dotfiles#home-manager -- switch --flake /nhm/dotfiles#admin
# Logeado como main 
nix run /nhm/dotfiles#home-manager -- switch --flake /nhm/dotfiles#main
# Logeado como safe
nix run /nhm/dotfiles#home-manager -- switch --flake /nhm/dotfiles#safe

Extra

Si estas en /nhm/dotfiles se puede usar:

nix run .#home-manager -- switch --flake .#admin

Notas útiles

  • Update:
cd /nhm/dotfiles
nix flake update                     # refresca nixpkgs/home-manager en flake.lock
# aplica por usuario:
nix run .#home-manager -- switch --flake .#admin
nix run .#home-manager -- switch --flake .#main
nix run .#home-manager -- switch --flake .#safe
  • HM:
home-manager generations
home-manager switch --rollback
  • Limpieza:
sudo nix store gc
# Por usuario
home-manager expire-generations "-30 days"

Monero Node


Store Monero Node on an external drive.

  • First, do the same as in the LUKS guide for the drive.
  • Assuming that /dev/sdb is the drive

Tux

If you don’t use sudo, just change it to sudo

Preparing the Drive

sudo fdisk /dev/sdb
n
# Enter
# Enter
# Enter
# Enter
w

Optional encryption

sudo cryptsetup luksFormat /dev/sdb1
sudo cryptsetup open /dev/sdb1 a
sudo mkfs.ext4 /dev/mapper/a
sudo cryptsetup close a
sync 

Downloading monerod

Install monerod in your distro of choice

# In Archlinux
sudo pacman -S monero
# In Debian 
sudo apt install monero
# With Homebrew
brew install monero

or

In other distros install wget and ->

wget https://downloads.getmonero.org/gui/linux64
# Or if you prefer only cli
wget https://downloads.getmonero.org/cli/linux64
tar -xvf linux64
# ...
sudo cp monerod /usr/local/bin/
sudo cp monero-wallet-cli /usr/local/bin/
# Or just
sudo mv monero* /usr/local/bin/

or

Recommended to create a user without sudo for only monero

Setting up Monero

sudo useradd --system --shell /usr/sbin/nologin --home-dir /var/lib/monero monero

sudo mkdir -p /mnt/monero-node/
sudo mount /dev/xxx /mnt/monero-node
sudo mkdir -p /mnt/monero-node/.bitmonero   # Your blockchain storage location
sudo mkdir -p /var/log/monero               # Log directory
sudo mkdir -p /etc/monero                   # Configuration directory
sudo mkdir -p /run/monero
sudo chown monero:monero /run/monero

# Set ownership for blockchain directory
sudo chown -R monero:monero /mnt/monero-node/.bitmonero
sudo chmod 750 /mnt/monero-node/.bitmonero

# Set ownership for log directory
sudo chown -R monero:monero /var/log/monero
sudo chmod 750 /var/log/monero

# Create the monerod configuration file
sudo vim /etc/monero/monerod.conf

sudo chown root:monero /etc/monero/monerod.conf
sudo chmod 640 /etc/monero/monerod.conf

Firewall

sudo firewall-cmd --permanent --add-port=18089/tcp --zone=drop
sudo firewall-cmd --reload

Run Monerod

There are 2 alternatives; Service or Terminal

Monerod Service

# Create the systemd service file
sudo vim /etc/systemd/system/monerod.service
sudo systemctl daemon-reload
sudo systemctl enable monerod
sudo systemctl start monerod
sudo systemctl status monerod

Monerod in Terminal

sudo -u monero /usr/local/bin/monerod --config-file=/etc/monero/monerod.conf

Homebrew (In Linux)

sudo -u monero /home/linuxbrew/.linuxbrew/bin/monerod --config-file=/etc/monero/monerod.conf

Cli Wallet

monero-wallet-cli --trusted-daemon --daemon-login username

Monero Ban List

Github repo

In monero

Cake Wallet


sha256sum Cake_Wallet_v5.1.2_Linux.tar.xz # Check in the release page
tar -xvf Cake_Wallet_v5.1.2_Linux.tar.xz
sudo mv Cake_Wallet*Linux /opt/cakewallet

Entrada de escritorio

sudo hx ~/.local/share/applications/cakewallet.desktop

Copia esto:

[Desktop Entry]
Version=1.0
Type=Application
Name=CakeWallet
Comment=Wallet (CakeWallet Desktop)
Exec=/opt/cakewallet/cake_wallet %U
Icon=/opt/cakewallet/data/flutter_assets/assets/images/cake_logo_dark.svg
Terminal=false
Categories=Finance;Wallet;Cryptocurrency;
StartupNotify=true