Showing posts with label debian. Show all posts
Showing posts with label debian. Show all posts

Saturday, May 30, 2026

Java: enumerate com serial using fazecast jSerialComm

Simple code to enumerate serial com port


/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 */

package com.dedetok.enumcomport;

import com.fazecast.jSerialComm.SerialPort;

/**
 *
 * @author dedetok
 */
public class EnumComPort {

    public static void main(String[] args) {
        System.out.println("Hello World!");

        SerialPort[] ports = SerialPort.getCommPorts();

        if (ports.length == 0) {
            System.out.println("No serial ports detected.");
            return;
        }

        System.out.println("Available Serial Ports:");
        System.out.println("------------------------");

        for (SerialPort port : ports) {

            System.out.println("System Port Name : " + port.getSystemPortName());
            System.out.println("Descriptive Name: " + port.getDescriptivePortName());
            System.out.println("Port Description: " + port.getPortDescription());
            System.out.println("System Location : " + port.getSystemPortPath());
            System.out.println("------------------------");
        }
        
    }
}

 

Java: Hook shutdown to run java application as systemd

This is minimum java code to hook shutdown


/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 */

package com.dedetok.javasertvicetest;

/**
 *
 * @author dedetok
 */
public class JavaSertviceTest {

    private static volatile boolean running = true;
        
    public static void main(String[] args) {
        System.out.println("Hello World!");
        
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("Shutdown hook triggered");

            running = false;

            // Cleanup resources here
            // Close database connections
            // Flush logs
            // Stop worker threads
            // Main shutdown path
            //cleanupResources();

            System.out.println("Cleanup complete");
        }));

        System.out.println("Daemon started");

        while (running) {
            System.out.println("Working...");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ex) {
                System.getLogger(JavaSertviceTest.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex);
            }
        }

    }
}

to run/test this application, you can not run it inside netbeans. use terminal to run it, go to your project root and run


$ java -cp target/classes \
     com.dedetok.javasertvicetest.JavaSertviceTest
Hello World!
Daemon started
Working...
Working...
^CShutdown hook triggered
Cleanup complete

 

 

Java Netbeans: upgrade binary Netbeans 29 to Netbeans 30

 This step is straight forward:

  1. go to your root directory (e.g your home dir ~/), and rename old folder e.g ~/netbeans29.
  2. extract netbeans 30 binary and put it in root directory to replace old folder (e.g your home dir ~/).
  3. Run your netbeans 30, import previous configuration
  4. if no error found you safe to remove
    1. old netbeans 29 (e.g ~/netbeans29) 
    2. ~/.netbeans/29
    3. ~/.cache/netbeans/29

 

Sunday, May 24, 2026

Java: using maven in Debian 13

Apache Maven is an open-source build automation and project management tool primarily used for Java applications. It simplifies the development process by managing a project's build, reporting, and documentation from a single piece of information.

To install maven:

# apt install maven
Installing:                     
  maven

Installing dependencies:
...

Showing version

$ mvn --version
Apache Maven 3.9.9
Maven home: /usr/share/maven
Java version: 21.0.11, vendor: Debian, runtime: /usr/lib/jvm/java-21-openjdk-amd64
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "6.12.88+deb13-amd64", arch: "amd64", family: "unix"

Go to your workspace, and run

$ mvn archetype:generate \
  -DgroupId=com.dedetok.myapp \
  -DartifactId=myapp \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DarchetypeVersion=1.5 \
  -DinteractiveMode=false
...
$ ls myapp
pom.xml  src

DartifactId=myapp -> project root directory.

The main java code is ~/myapp/src/main/java/com/dedetok/myapp/App.java

package com.dedetok.myapp;

/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

To run the project using mvn, go to folder myapp, edit pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.dedetok</groupId>
    <artifactId>myapp</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.6.3</version>
                <configuration>
                    <mainClass>com.dedetok.myapp.App</mainClass>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.4.2</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.dedetok.myapp.App</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

then run:

$ mvn package

Run your application 


$ mvn exec:java -Dexec.mainClass="com.dedetok.myapp.App"
[INFO] Scanning for projects...
[INFO] 
[INFO] --------------------------< com.dedetok:myap >--------------------------
[INFO] Building myap 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- exec:3.6.3:java (default-cli) @ myap ---
Hello World!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  8.265 s
[INFO] Finished at: 2026-05-24T14:59:08+07:00
[INFO] -----------------------------------------

or

$ mvn exec:java
[INFO] Scanning for projects...
[INFO] 
[INFO] -------------------------< com.dedetok:myapp >--------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- exec:3.6.3:java (default-cli) @ myapp ---
Hello World!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.712 s
[INFO] Finished at: 2026-05-25T14:43:48+07:00
[INFO] ------------------------------------------------------------------------

To use old school java, copy library needed

$ mvn dependency:copy-dependencies

run using java


$ mvn compile
$ java -cp "target/classes:target/dependency/*" com.dedetok.myapp.App
Hello World!

 

 

 

Tuesday, May 19, 2026

Debian 13: configurating Syris RD200-M1-G v01.55 Card Reader Part 2, detecting card reader in Debian

Add you as group of dialout (20)


# usermod -aG dialout myuser
# usermod -aG uucp myuser
# usermod -aG lock myuser
# usermod -aG tty myuser

Note: 

  1. All of these groups may not exist on every Linux distro. (Note, this process must only be done once for each user)
  2. if you use terminal only, this will effect directly, but if you use window Manager, you require to logout and re-login to make it effect especially on Netbeans, If aftar re-login fail, try restart.  

Confirm which com the reader assign


# ls -l /dev/ttyACM0
crw-rw---- 1 root dialout 166, 0 May 19 13:43 /dev/ttyACM0

The card reader assign com at /dev/ttyACM0

This is simple java code to read card when tap on device


import com.fazecast.jSerialComm.SerialPort;
import java.io.InputStream;
import java.io.OutputStream;

/**
 *
 * @author dedetok
 */
public class DedetokSerialCom {

    static private SerialPort serialPort;
    static private int boudRate = 115200;
            
    public static void main(String[] args) {
        System.out.println("Hello World!");
        
        serialPort = SerialPort.getCommPort("/dev/ttyACM0");
        
        // Configure serial port
        serialPort.setBaudRate(boudRate);
        serialPort.setNumDataBits(8);
        serialPort.setNumStopBits(SerialPort.ONE_STOP_BIT);
        serialPort.setParity(SerialPort.NO_PARITY);
        
        // Optional timeouts
        serialPort.setComPortTimeouts(
                SerialPort.TIMEOUT_READ_SEMI_BLOCKING,
                1000,
                0
        );
        
        
        // Open port
        if (!serialPort.openPort()) {
            System.out.println("Failed to open port");
            return;
        }
        
        System.out.println("Port opened"); // debug
                
        // ------------------read mifare id card ----------------------
        System.out.println("MIFARE"); // debug
        // STX LEN CMD
        byte[] cmd = new byte[] {
                (byte)0x02, // STX
                (byte)0x01, // LEN
                (byte)0x11  // CMD Read UID
        };
        
        // Send
        serialPort.writeBytes(cmd, cmd.length);

        System.out.println("command Send"); // debug
        
        /*
        02 02 11 10 : command error
        02 02 11 01 : no card
        02 06 11 00 xx xx xx xx : mifare id xx xx xx xx
        */

        byte[] rx = new byte[64];

        int n = serialPort.readBytes(rx, rx.length);

        System.out.println("Received bytes: " + n);

                // Print raw HEX
        for (int i = 0; i < n; i++) {
            System.out.printf("%02X ", rx[i]);
        }
        System.out.println();

        // ------------------read ISO15693 inventory card ----------------------
        // NOT SUPPORTED


        System.out.println();

        serialPort.closePort();

        
        System.out.println("Port Closed"); // debug
    }
}

This is sample output with uid masked Netbeans


Hello World!
Port opened
MIFARE
command Send
Received bytes: 8
02 06 xx xx xx xx xx 52 

What are they?

02 STX
06 LENGTH
Data 1-5 xx xx xx xx xx
Checksum 52 

e.g. to read Mifare UID (0x11)

command in bytes: 02 01 11

02: run command

01: length

11: command to read Mifare UID

10 checksum ( 01 xor 11 )

if return 4 bytes: MIFARE Classic 1K/4K

if return 7 bytes: NTAG / Ultralight / DESFire

if return 8 bytes: ISO15693

Example response 4 bytes UID (classic mifare)


02 06 01 xx xx xx xx 8E 
 |  |  |  |           |
 |  |  |  |           -> checksum
 |  |  |  -------------> data uid
 |  |  ----------------> status 
 |  -------------------> length data
 ----------------------> STX

Example response 6 bytes UID


02 0A 11 00 xx xx xx xx xx xx 80 00
 |  |  |  |                    |  |
 |  |  |  |                    |  -> SAK
 |  |  |  |                    ----> checksum
 |  |  |  -------------------------> data uid
 |  |  ----------------------------> status
 |  -------------------------------> length data
 ----------------------------------> STX

 

 

 

Debian 13: configurating Syris RD200-M1-G v01.55 Card Reader Part 1, firmware upgrade

By default Syris RD200-M1-G v01.55 run in keyboard mode. It will send to text when card detected. 

You need to upgrade the firmware for support some new card and change it to com mode. At com mode, you can communication with card to utilize it.

DO THIS IN WINDOWS TO UPDATE FIRMWARE:

All documentation link provided by syris is https://syris.com/ftp/index.php. Goto SYRIS_RFID_DVD -> RD200_300 -> USB_ReaderTools
_V0291.rar (All tools and docs), download and extract. 

Inside RD200_RD300_SDK_V0193 -> UtilityTools -> FirmwareFiles, there are 2 directory v1 and v2:

  • RD200(v1)
    • RD200_M1_COM_V0271_20230901.SYB
    • RD200_M1_V0271_20230901.SYB 
  • RD200(v2)
    • RD200-M1-V2_V0290_20250603.SYB
    • RD200-M1-V2_V0291_20251029_01.SYB
    • RD200-M1-V2-COM_V0283_20240216.SYB 

Run USB_ReaderTools_V0291_20251029.exe, go to tab firmware and use RD200_M1_COM_V0271_20230901.SYB to RD200-M1-G v01.55. If you choose wrong firmware, the tools will warn you "firmware type error". upgrade it, wait until finish.

After firmware upgraded, you need to change Auto Usb to Com, e.g. com3,(RD200-M1 0155) 12110056 -> (RD200-M1 0271) 12110056

Windows part is done.

This is Debian before upgrade and change to com mode


# dmesg
[  841.193326] usb 8-1: new full-speed USB device number 2 using xhci_hcd
[  841.349102] usb 8-1: New USB device found, idVendor=0e6a, idProduct=0317, bcdDevice= 1.40
[  841.349118] usb 8-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  841.349126] usb 8-1: Product: USB Reader
[  841.349133] usb 8-1: Manufacturer: SYRIS Technology Corp.
[  841.349139] usb 8-1: SerialNumber: 00000000
[  841.389585] input: SYRIS Technology Corp. USB Reader as /devices/pci0000:00/0000:00:08.3/0000:06:00.4/usb8/8-1/8-1:1.0/0003:0E6A:0317.0004/input/input23
[  841.505357] hid-generic 0003:0E6A:0317.0004: input,hidraw3: USB HID v1.10 Keyboard [SYRIS Technology Corp. USB Reader] on usb-0000:06:00.4-1/input0
[  841.522787] input: SYRIS Technology Corp. USB Reader Consumer Control as /devices/pci0000:00/0000:00:08.3/0000:06:00.4/usb8/8-1/8-1:1.1/0003:0E6A:0317.0005/input/input24
[  841.577455] input: SYRIS Technology Corp. USB Reader System Control as /devices/pci0000:00/0000:00:08.3/0000:06:00.4/usb8/8-1/8-1:1.1/0003:0E6A:0317.0005/input/input25
[  841.577717] hid-generic 0003:0E6A:0317.0005: input,hidraw4: USB HID v1.10 Device [SYRIS Technology Corp. USB Reader] on usb-0000:06:00.4-1/input1
# lsusb
...
Bus 008 Device 002: ID 0e6a:0317 Megawin Technology Co., Ltd USB Reader
...
# lsusb -v -d 0e6a:0317

Bus 008 Device 002: ID 0e6a:0317 Megawin Technology Co., Ltd USB Reader
Negotiated speed: Full Speed (12Mbps)
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 [unknown]
  bDeviceSubClass         0 [unknown]
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x0e6a Megawin Technology Co., Ltd
  idProduct          0x0317 USB Reader
  bcdDevice            1.40
  iManufacturer           1 SYRIS Technology Corp.
  iProduct                2 USB Reader
  iSerial                 3 00000000
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0042
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      1 Keyboard
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 (null)
          wDescriptorLength      73
          Report Descriptors: 
            ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              10
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 [unknown]
      bInterfaceProtocol      0 
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 (null)
          wDescriptorLength     861
          Report Descriptors: 
            ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x03  EP 3 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
Device Status:     0x0000
  (Bus Powered)

After firmware upgrade and com mode


# dmesg
[   65.250090] usb 8-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[   65.250095] usb 8-1: Product: USB Reader
[   65.250098] usb 8-1: Manufacturer: SYRIS Technology Corp.
[   65.293079] cdc_acm 8-1:1.0: ttyACM0: USB ACM device
[   65.293108] usbcore: registered new interface driver cdc_acm
[   65.293110] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN 
# lsusb
...
Bus 008 Device 002: ID 0e6a:0316 Megawin Technology Co., Ltd USB Reader
...
# lsusb -v -d 0e6a:0316
Bus 008 Device 002: ID 0e6a:0316 Megawin Technology Co., Ltd USB Reader
Negotiated speed: Full Speed (12Mbps)
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            2 Communications
  bDeviceSubClass         0 [unknown]
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x0e6a Megawin Technology Co., Ltd
  idProduct          0x0316 USB Reader
  bcdDevice            1.06
  iManufacturer           1 SYRIS Technology Corp.
  iProduct                2 USB Reader
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0043
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         2 Communications
      bInterfaceSubClass      2 Abstract (modem)
      bInterfaceProtocol      1 AT-commands (v.25ter)
      iInterface              0 
      CDC Header:
        bcdCDC               1.10
      CDC Call Management:
        bmCapabilities       0x01
          call management
        bDataInterface          1
      CDC ACM:
        bmCapabilities       0x06
          sends break
          line coding and serial state
      CDC Union:
        bMasterInterface        0
        bSlaveInterface         1 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval              16
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass        10 CDC Data
      bInterfaceSubClass      0 [unknown]
      bInterfaceProtocol      0 
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x03  EP 3 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
Device Status:     0x0000
  (Bus Powered)

 

 

Friday, May 1, 2026

lamp debian 13: configure codeigniter 4


Minimum codeigniter 4.7.2: php 8.2

Target access http://localhost/app1 

Download zip codeiginiter 4 from official site and extract into folder root e.g. /home/[username]/ci4/app1.

Install required php php-mbstring

# apt install php-intl php-mbstring
# systemctl restart apache2

The following PHP extensions should be enabled on your server:

  • php-curl
  • php-json
  • php-mysqlnd/php-mysql
  • php-imagick php-gd
  • php-xml/php-simplexml

Default root folder

+-- app
+-- public
+-- tests
+-- spark
+-- system
+-- writable
|
+composer.json
+env
+LICENSE
+preload.php
+phpunit.xml.dist
+README.md

Change group and permission:


# usermod -a -G www-data [username]
# groups [username]
[username] : [username] cdrom floppy audio dip www-data video plugdev users netdev bluetooth lpadmin scanner libvirt
# chgrp www-data /home/[username] /home/[username]/ci4 /home/[username]/ci4/app1
# chmod g+x /home/[username] /home/[username]/ci4 /home/[username]/ci4/app1 

Edit /home/[username]/ci4/app1/app/Config/


<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class App extends BaseConfig
{
    /**
     * --------------------------------------------------------------------------
     * Base Site URL
     * --------------------------------------------------------------------------
     *
     * URL to your CodeIgniter root. Typically, this will be your base URL,
     * WITH a trailing slash:
     *
     * E.g., http://example.com/
     */
    //public string $baseURL = 'http://localhost:8080/';
    public string $baseURL = 'http://localhost/app1/';


Option 1 Using subpath in user home folder

assume your root codeigniter is /home/[username]/ci4/app1

edit file /etc/apache2/sites-enabled/000-default.conf and restart


    <virtualhost>
	# The ServerName directive sets the request scheme, hostname and port that
	# the server uses to identify itself. This is used when creating
	# redirection URLs. In the context of virtual hosts, the ServerName
	# specifies what hostname must appear in the request's Host: header to
	# match this virtual host. For the default virtual host (this file) this
	# value is not decisive as it is used as a last resort host regardless.
	# However, you must set it for any further virtual host explicitly.
	#ServerName www.example.com

	ServerAdmin webmaster@localhost
	DocumentRoot /var/www/html

        # --- SUBPATH
        Alias /app1 /home/[username]/ci4/app1/public
        <directory app1="" ci4="" home="" public="" username="">
           Options Indexes FoolowSymLinks
           AllowOverride All
           Require all granted
        </directory>

~# apache2ctl configtest
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message
Syntax OK
~# systemctl restart apache2

No configuration in this option.

Option 2 Using subpath in copy public folder to /var/www/html/ 

this is close to shared web hosting

create folder app1 inside /var/www/html and move all content inside [ci4_project_root]/public  into app1

Edit file index.php


/*
 *---------------------------------------------------------------
 * BOOTSTRAP THE APPLICATION
 *---------------------------------------------------------------
 * This process sets up the path constants, loads and registers
 * our autoloader, along with Composer's, loads our constants
 * and fires up an environment-specific bootstrapping.
 */

// LOAD OUR PATHS CONFIG FILE
// This is the line that might need to be changed, depending on your folder structure.
//require FCPATH . '../app/Config/Paths.php'; // NOT USED
// ^^^ Change this line if you move your application folder 
// USE ABOSOLUTE PATH
require '/home/[username]/ci4/app1/app/Config/Paths.php'; 

You may do this in web shared hosting. the deference is /var/www/html and /home/[username]/public_html (usually in cpanel).

NOTE: choose one of the options above, don't mix it.

Using Sub domain e.g. app1.example.com (not tested)

Subdomain Method (Best Practice)

This is the cleaner and more secure method as it keeps the entire framework structure intact.

Steps:

  1. Upload and extract your CodeIgniter zip into the folder you specified above e.g. /home/[username]/ci4/app1/.
  2. In cPanel/Plesk, create a Subdomain (e.g., app1.domain.com).
  3. Set its Document Root for sub domain to the public folder of your project (e.g., /home/[username]/ci4/app1/public) .
  4. No code changes are needed. Your setup is complete.

For development, you can find file name env. Edit it, set CI_ENVIRONMENT = development (default is production), save it as .env (with . in leading file name).

 

Debian 13: configure php apache environment for personal development

Add user to group of www-data (this is example for CodeIgniter 4 Framework)

# usermod -a -G www-data [username]
# groups [username]
[username] : [username] cdrom floppy audio dip www-data video plugdev users netdev bluetooth lpadmin scanner libvirt
# chgrp www-data /home/[username] /home/[username]/ci4 /home/[username]/ci4/app1
# chmod g+x /home/[username] /home/[username]/ci4 /home/[username]/ci4/app1

Folder structure for code igniter api

/home/[username]/ci4/app1
|
+-- app
+-- public
+-- tests
+-- spark
+-- system
+-- writable
|
+composer.json
+env
+LICENSE
+preload.php
+phpunit.xml.dist
+README.md    

Assume apache already installed, edit file /etc/apache2/sites-enabled/000-default.conf and add virtual folder e.g localhost/app1


    <virtualhost>
	# The ServerName directive sets the request scheme, hostname and port that
	# the server uses to identify itself. This is used when creating
	# redirection URLs. In the context of virtual hosts, the ServerName
	# specifies what hostname must appear in the request's Host: header to
	# match this virtual host. For the default virtual host (this file) this
	# value is not decisive as it is used as a last resort host regardless.
	# However, you must set it for any further virtual host explicitly.
	#ServerName www.example.com

	ServerAdmin webmaster@localhost
	DocumentRoot /var/www/html

        # --- SUBPATH
        Alias /app1 /home/[username]/ci4/app1/public
        <directory app1="" ci4="" home="" public="" username="">
           Options Indexes FoolowSymLinks
           AllowOverride All
           Require all granted
        </directory>

~# apache2ctl configtest
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message
Syntax OK

Replace [username] with yours

Restart apache


Monday, April 6, 2026

Debian 13: trouble shooting Android Debug Bridge (adb) on kernel 6.12.74

After i upgrade the kernel from 6.12.67 to kernel 6.12.74, the kernel can not detect my phone to test android application.

Do this using command

# modprobe cdc-acm
# modprobe usb-storage
# modprobe usbserial
# usermod -aG plugdev [username]
$ groups [username]
[username] : [username] cdrom floppy audio dip video plugdev users netdev bluetooth lpadmin scanner libvirt

make sure [username] in group of plugdev


Thursday, March 12, 2026

Debian 13: installing google chrome

google chrome system requirements for debian

  • Release: Debian 10+
  • Processor: Intel Pentium 4 or later that is SSE3 capable 64-bit
  • RAM: 2GB is a minimum in some contexts, 4GB or more is recommended.
  • Storage: At least 16GB, though 32GB or more is recommended for optimal performance. 

 Download key and configure apt sources  

~# wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo tee /etc/apt/trusted.gpg.d/google.asc >/dev/null
~# ls /etc/apt/trusted.gpg.d/ | grep google
google.asc
google-chrome.gpg
~# curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /usr/share/keyrings/google-chrome.gpg
~# echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list > /dev/null

Update repository

~# apt update
Hit:1 http://deb.debian.org/debian trixie-backports InRelease
Hit:2 https://deb.debian.org/debian trixie InRelease   
Hit:3 https://deb.debian.org/debian trixie-updates InRelease
Hit:4 https://dl.google.com/linux/chrome/deb stable InRelease       
Hit:5 https://security.debian.org/debian-security trixie-security InRelease
Hit:6 http://httpredir.debian.org/debian trixie InRelease
All packages are up to date
~# ls /etc/apt/sources.list.d/
google-chrome.list

Installing google chrome stable

~# apt install  google-chrome-stable 
Installing:                     
  google-chrome-stable

Summary:
  Upgrading: 0, Installing: 1, Removing: 0, Not Upgrading: 0
  Download size: 127 MB
  Space needed: 413 MB / 18.9 GB available

Get:1 https://dl.google.com/linux/chrome/deb stable/main amd64 google-chrome-stable amd64 146.0.7680.71-1 [127 MB]
Fetched 127 MB in 57s (2,254 kB/s)                                             
Selecting previously unselected package google-chrome-stable.
(Reading database ... 189434 files and directories currently installed.)
Preparing to unpack .../google-chrome-stable_146.0.7680.71-1_amd64.deb ...
Unpacking google-chrome-stable (146.0.7680.71-1) ...
Setting up google-chrome-stable (146.0.7680.71-1) ...
update-alternatives: using /usr/bin/google-chrome-stable to provide /usr/bin/x-w
ww-browser (x-www-browser) in auto mode
update-alternatives: using /usr/bin/google-chrome-stable to provide /usr/bin/gno
me-www-browser (gnome-www-browser) in auto mode
update-alternatives: using /usr/bin/google-chrome-stable to provide /usr/bin/goo
gle-chrome (google-chrome) in auto mode
Processing triggers for man-db (2.13.1-1) ...
Processing triggers for desktop-file-utils (0.28-1) ...

Done.... 

Sunday, March 1, 2026

Debian 13: upgrading bios

Is it possible to upgrade bios from Debian, since the most manufacture only provide bios upgrade under windows environment? In the past it is impossible. But today, it can for some systems. Here is the way to check and upgrade bios from bios. you need root or sudo, i use root user.

Install software

# apt install fwupd

Check your bios

# dmidecode 3.6
Getting SMBIOS data from sysfs.
SMBIOS 3.4.0 present.

Handle 0x0000, DMI type 0, 26 bytes
BIOS Information
    Vendor: LENOVO
    Version: JNCN52WW(V2.12)
    Release Date: 10/04/2024 <- your release date
    Address: 0xE0000
    Runtime Size: 128 kB
    ROM Size: 32 MB
    Characteristics:
        PCI is supported
        BIOS is upgradeable
        BIOS shadowing is allowed
        Boot from CD is supported
        Selectable boot is supported
        EDD is supported
        Japanese floppy for NEC 9800 1.2 MB is supported (int 13h)
        Japanese floppy for Toshiba 1.2 MB is supported (int 13h)
        5.25"/360 kB floppy services are supported (int 13h)
        5.25"/1.2 MB floppy services are supported (int 13h)
        3.5"/720 kB floppy services are supported (int 13h)
        3.5"/2.88 MB floppy services are supported (int 13h)
        8042 keyboard services are supported (int 9h)
        CGA/mono video services are supported (int 10h)
        ACPI is supported
        USB legacy is supported
        BIOS boot specification is supported
        Targeted content distribution is supported
        UEFI is supported
    BIOS Revision: 1.52
    Firmware Revision: 1.52

Handle 0x001C, DMI type 13, 22 bytes
BIOS Language Information
    Language Description Format: Long
    Installable Languages: 4
        en|US|iso8859-1
        fr|FR|iso8859-1
        ja|JP|unicode
        zh|TW|unicode
    Currently Installed Language: en|US|iso8859-1

To show product name and version

# cat /sys/class/dmi/id/product_name
82SB
# cat /sys/class/dmi/id/product_version
IdeaPad Gaming 3 15ARH7

Check device  

# fwupdmgr get-devices
LENOVO 82SB

├─AMD Ryzen 5 7535HS with Radeon Graphics:
│ │   Device ID:          4bde70ba4e39b28f9eab1628f9dd6e6244c03027
│ │   Vendor:             Advanced Micro Devices, Inc.
│ │   GUIDs:              52f8f9af-1ca9-5352-bef4-ceb232c888a5 ← CPUID\PRO_0&FAM_19&MOD_44
│ │                       e94372a3-3ffb-5d1c-a579-c415b7313e52 ← CPUID\PRO_0&FAM_19&MOD_44&STP_1
│ │   Device Flags:       • Internal device
│ │ 
│ ├─Secure Processor:
│ │     Device ID:        c54ab0237d7a8db8c717b68e0be78e4374a2a079
│ │     Current version:  00.28.00.71
│ │     Bootloader Version: 00.28.00.71
│ │     Vendor:           Advanced Micro Devices, Inc. (PCI:0x1022)
│ │     GUID:             9844da3e-1df2-52fe-9413-d4378af6221e ← PCI\VEN_1022&DEV_1649
│ │     Device Flags:     • Internal device
│ │                       • Can tag for emulation
│ │   
│ └─System Management Unit (SMU):
│       Device ID:        db0330716216c629bb2c07256e5d018f499eb6ce
│       Summary:          Microcontroller used within CPU/APU program 4
│       Current version:  69.63.0
│       Vendor:           Advanced Micro Devices, Inc.
│       GUID:             79307ae6-a2ea-52e1-bf56-6abbaf3547ad ← /sys/devices/platform/AMDI0007:00
│       Device Flags:     • Internal device
│                         • Can tag for emulation
│     
├─GA107 [GeForce RTX 2050]:
│     Device ID:          ce4c74a5188d5b9cdb1e72ed32dad2d313c1c999
│     Current version:    a1
│     Vendor:             NVIDIA Corporation (PCI:0x10DE)
│     GUID:               68e82ae9-e3f2-5996-ba6b-9054136e6d65 ← PCI\VEN_10DE&DEV_25AD
│     Device Flags:       • Internal device
│                         • Cryptographic hash verification is available
│                         • Can tag for emulation
│   
├─Micron MTFDKCD512QFM-1BD1AABLA:
│     Device ID:          04e17fcf7d3de91da49a163ffe4907855c3648be
│     Summary:            NVM Express solid state drive
│     Current version:    1002V3LN
│     Vendor:             Micron Technology Inc (PCI:0x1344)
│     Serial Number:      22453C44BE0D
│     Problems:           • Device requires AC power to be connected
│     GUIDs:              84b40af9-5392-5d04-ab7a-92c6ecd85f9f ← NVME\VEN_1344&DEV_5413
│                         518236e8-44dc-5c54-86bf-8ab9c098cd5e ← NVME\VEN_1344&DEV_5413&SUBSYS_13441100
│                         2f40d3c1-c50e-5e7f-aa6c-9cbef7c3679f ← Micron MTFDKCD512QFM-1BD1AABLA
│     Device Flags:       • Internal device
│                         • System requires external power source
│                         • Needs a reboot after installation
│                         • Device is usable for the duration of the update
│                         • Updatable
│                         • Can tag for emulation
│   
├─System Firmware:
│ │   Device ID:          c74868c50fe146f6d80a0978b8140db47f89c95a
│ │   Summary:            UEFI System Resource Table device (updated via NVRAM)
│ │   Current version:    1879441490
│ │   Minimum Version:    1380122624
│ │   Vendor:             LENOVO (DMI:LENOVO)
│ │   Update State:       Success
│ │   Problems:           • Device requires AC power to be connected
│ │   GUID:               b287b6c8-7a87-48d7-9316-da7a121e91c6
│ │   Device Flags:       • Internal device
│ │                       • System requires external power source
│ │                       • Needs a reboot after installation
│ │                       • Cryptographic hash verification is available
│ │                       • Device is usable for the duration of the update
│ │                       • Updatable
│ │   Device Requests:    • Message
│ │ 
│ ├─Ideapad Products:
│ │     Device ID:        6924110cde4fa051bfdc600a60620dc7aa9d3c6a
│ │     Summary:          UEFI Platform Key
│ │     Current version:  0
│ │     Vendor:           Unknown
│ │     GUID:             a5ace873-b5ff-5d82-9051-52a46d71b6a4 ← UEFI\CRT_D1FA4BAE5073E699B7D04455F4F1126530BD69A4
│ │     Device Flags:     • Internal device
│ │                       • Cryptographic hash verification is available
│ │                       • Can tag for emulation
│ │   
│ ├─UEFI Signature Database:
│ │ │   Device ID:        0352a8acc949c7df21fec16e566ba9a74e797a97
│ │ │   Device Flags:     • Internal device
│ │ │ 
│ │ └─Windows Production PCA:
│ │       Device ID:      ea9d4960094c43d107b919fe44941f2c774f84df
│ │       Current version: 2011
│ │       Vendor:         Microsoft (UEFI:Microsoft)
│ │       GUIDs:          675d2184-6c9a-59f1-a6f1-3c229b5dbb79 ← UEFI\VENDOR_Microsoft&NAME_Microsoft-Windows-Production-PCA
│ │                       1a84097f-714e-51b7-b293-9a803c98bb1d ← UEFI\CRT_CBBBF4B136DB90D11FD37A4A9B2106973AECC095
│ │       Device Flags:   • Internal device
│ │                       • Updatable
│ │                       • Signed Payload
│ │                       • Can tag for emulation
│ │     
│ └─UEFI dbx:
│       Device ID:        362301da643102b9f38477387e2193e57abaa590
│       Summary:          UEFI revocation database
│       Current version:  20230301
│       Minimum Version:  20230301
│       Vendor:           UEFI:Microsoft
│       Install Duration: 1 second
│       GUID:             f8ba2887-9411-5c36-9cee-88995bb39731 ← UEFI\CRT_A1117F516A32CEFCBA3F2D1ACE10A87972FD6BBE8FE0D0B996E09E65D802A503&ARCH_X64
│       Device Flags:     • Internal device
│                         • Updatable
│                         • Needs a reboot after installation
│                         • Cryptographic hash verification is available
│                         • Device is usable for the duration of the update
│                         • Only version upgrades are allowed
│                         • Signed Payload
│                         • Can tag for emulation
│     
├─TPM:
│     Device ID:          1d8d50a4dbc65618f5c399c2ae827b632b3ccc11
│     Current version:    6.20.0.6
│     Vendor:             Advanced Micro Devices, Inc. (TPM:AMD)
│     GUIDs:              9305de1c-1e12-5665-81c4-37f8e51219b8 ← TPM\VEN_AMD&DEV_0001
│                         78a291ae-b499-5b0f-8f1d-74e1fefd0b1c ← TPM\VEN_AMD&MOD_AMD
│                         65a3fced-b423-563f-8098-bf5c329fc063 ← TPM\VEN_AMD&DEV_0001&VER_2.0
│                         5e704f0d-83cb-5364-8384-f46d725a23b8 ← TPM\VEN_AMD&MOD_AMD&VER_2.0
│     Device Flags:       • Internal device
│                         • System requires external power source
│                         • Needs a reboot after installation
│                         • Device can recover flash failures
│                         • Full disk encryption secrets may be invalidated when updating
│                         • Signed Payload
│                         • Can tag for emulation
│   
├─UEFI Device Firmware:
│     Device ID:          e78fe7874aa72b14bc3138165829a0f046b925e4
│     Summary:            UEFI System Resource Table device (updated via NVRAM)
│     Current version:    0
│     Minimum Version:    1
│     Vendor:             DMI:LENOVO
│     Update State:       Success
│     Problems:           • Device requires AC power to be connected
│     GUID:               a9898afa-ef58-48fe-b09a-f476afce467c
│     Device Flags:       • Internal device
│                         • System requires external power source
│                         • Needs a reboot after installation
│                         • Device is usable for the duration of the update
│                         • Updatable
│     Device Requests:    • Message
│   
└─UEFI Device Firmware:
      Device ID:          cb1be209f9d53fed715391d7dcb894ba4d874719
      Summary:            UEFI System Resource Table device (updated via NVRAM)
      Current version:    3378443
      Vendor:             DMI:LENOVO
      Update State:       Success
      Problems:           • Device requires AC power to be connected
      GUID:               e18d48f3-8ed4-484e-8e01-cc33572399ff
      Device Flags:       • Internal device
                          • System requires external power source
                          • Needs a reboot after installation
                          • Device is usable for the duration of the update
                          • Updatable
      Device Requests:    • Message

Refresh firmware meta-data

# fwupdmgr refresh --force
Updating lvfs
Downloading…             [************************************** ]

Successfully downloaded new metadata: Updates have been published for 0 of 5 local devices

Perform upgrade

# fwupdmgr get-updates
Devices with no available firmware updates: 
 • Micron MTFDKCD512QFM-1BD1AABLA
 • System Firmware
 • UEFI Device Firmware
 • UEFI Device Firmware
 • KEK CA
 • OK Certificate
 • UEFI CA
 • UEFI dbx
 • Windows Production PCA
No updatable devices

 

Monday, February 23, 2026

Debian 13: debsecan to check vunerablities

This is MUST know for server admin.

Debin profide debsecan to analyzes the list of installed packages on the current host and reports vulnerabilities found on the system.

It runs locally and downloads vulnerability information over the Internet. It can send mail to interested parties when new vulnerabilities are discovered or when security updates become available. 

Installing debsecan

# apt install debsecan
Installing:                     
  debsecan

Using debsecan for linux-image (kernel)

# debsecan --suite trixie --only-fixed | grep -i linux-image 

If empty, don't have to upgrade linux-image 

e.g for 

CVE-2024-XXXXX linux-image-6.12.57+deb13-amd64 (high urgency)
CVE-2024-YYYYY linux-image-6.12.57+deb13-amd64 (medium urgency)

you MUST upgrade your linux-image, and plan for reboot system for kernel upgrade! 

 to list vulnerable software 

# debsecan --suite trixie --only-fixed --format packages
libavcodec59
libavfilter8
libavformat59
libavutil57
libpoppler126
libpostproc56
libssh-gcrypt-4
libswresample4
libswscale6
libvpx7
linux-headers-6.12.31-amd64
linux-headers-6.12.31-common
linux-headers-6.12.57+deb13-amd64
linux-headers-6.12.57+deb13-common
linux-kbuild-6.12.31
linux-kbuild-6.12.57+deb13

Note: they don't pose a runtime security risk to your system, but they are "out of date." . Consider to upgrade package.

Saturday, February 7, 2026

Debian 13: removing kernel left over after kernel upgrade

wifi and some device require compile in debian depend on kernel version. this documentation is intended as a small guide to tidy up your system.

list of ii and rc status of package

# uname -r
6.12.63+deb13-amd64
# dpkg -l | grep linux-image
rc  linux-image-6.1.0-33-amd64                         6.1.133-1                            amd64        Linux 6.1 for 64-bit PCs (signed)
rc  linux-image-6.1.0-34-amd64                         6.1.135-1                            amd64        Linux 6.1 for 64-bit PCs (signed)
rc  linux-image-6.1.0-37-amd64                         6.1.140-1                            amd64        Linux 6.1 for 64-bit PCs (signed)
rc  linux-image-6.1.0-9-amd64                          6.1.27-1                             amd64        Linux 6.1 for 64-bit PCs (signed)
rc  linux-image-6.12.38+deb13-amd64                    6.12.38-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
rc  linux-image-6.12.38+deb13-amd64-unsigned           6.12.38-1                            amd64        Linux 6.12 for 64-bit PCs
rc  linux-image-6.12.41+deb13-amd64                    6.12.41-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
rc  linux-image-6.12.41+deb13-amd64-unsigned           6.12.41-1                            amd64        Linux 6.12 for 64-bit PCs
rc  linux-image-6.12.43+deb13-amd64                    6.12.43-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
rc  linux-image-6.12.43+deb13-amd64-unsigned           6.12.43-1                            amd64        Linux 6.12 for 64-bit PCs
rc  linux-image-6.12.48+deb13-amd64                    6.12.48-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
rc  linux-image-6.12.48+deb13-amd64-unsigned           6.12.48-1                            amd64        Linux 6.12 for 64-bit PCs
rc  linux-image-6.12.57+deb13-amd64                    6.12.57-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
ii  linux-image-6.12.57+deb13-amd64-unsigned           6.12.57-1                            amd64        Linux 6.12 for 64-bit PCs
ii  linux-image-6.12.63+deb13-amd64                    6.12.63-1                            amd64        Linux 6.12 for 64-bit PCs (signed)
ii  linux-image-amd64                                  6.12.63-1                            amd64        Linux for 64-bit PCs (meta-package)

Note about rc and ii 

  • rc = package removed, but config files remain
  • ii = desired state install and current state installed 

we can conclude these packages are not used anymore but still exist in our system:

  1. rc linux-image-6.1.0-*
  2. rc linux-image-6.12.38*
  3. rc linux-image-6.12.41*
  4. rc linux-image-6.12.43*
  5. rc linux-image-6.12.48*

We can remove those packages which is kernel left over, using this command:

# dpkg -l | awk '/^rc  linux-image/ {print $2}' | xargs dpkg --purge
(Reading database ... 180811 files and directories currently installed.)
Purging configuration files for linux-image-6.1.0-33-amd64 (6.1.133-1) ...
Purging configuration files for linux-image-6.1.0-34-amd64 (6.1.135-1) ...
Purging configuration files for linux-image-6.1.0-37-amd64 (6.1.140-1) ...
Purging configuration files for linux-image-6.1.0-9-amd64 (6.1.27-1) ...
dpkg: warning: while removing linux-image-6.1.0-9-amd64, directory '/lib/modules' not empty so not removed
Purging configuration files for linux-image-6.12.38+deb13-amd64 (6.12.38-1) ...
Purging configuration files for linux-image-6.12.38+deb13-amd64-unsigned (6.12.38-1) ...
rmdir: failed to remove '/lib/modules/6.12.38+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.41+deb13-amd64 (6.12.41-1) ...
Purging configuration files for linux-image-6.12.41+deb13-amd64-unsigned (6.12.41-1) ...
rmdir: failed to remove '/lib/modules/6.12.41+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.43+deb13-amd64 (6.12.43-1) ...
Purging configuration files for linux-image-6.12.43+deb13-amd64-unsigned (6.12.43-1) ...
rmdir: failed to remove '/lib/modules/6.12.43+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.48+deb13-amd64 (6.12.48-1) ...
Purging configuration files for linux-image-6.12.48+deb13-amd64-unsigned (6.12.48-1) ...
rmdir: failed to remove '/lib/modules/6.12.48+deb13-amd64': No such file or directory
Purging configuration files for linux-image-6.12.57+deb13-amd64 (6.12.57-1) ...
I: /vmlinuz is now a symlink to boot/vmlinuz-6.12.63+deb13-amd64
I: /initrd.img is now a symlink to boot/initrd.img-6.12.63+deb13-amd64
rmdir: failed to remove '/lib/modules/6.12.57+deb13-amd64': Directory not empty

 

 

Saturday, January 31, 2026

Debian 13: using unbound as DNS over https resolver in conjuction with NetworkManager and Systemd Resolved

Assume:

  • NetworkManager and Systemd-Resolved already work 

Install unbound

# apt-get install unbound

Edit /etc/systemd/resolved.conf and set:

[Resolve]
DNS=127.0.0.1:5335
Domains=~.

Make sure this line in /etc/unbound/unbound.conf

...
include-toplevel: "/etc/unbound/unbound.conf.d/*.conf"
...

Create and edit /etc/unbound/unbound.conf.d/google-doh.conf

server:
    # Port 5335 is safer for laptops than 5353 (mDNS)
    port: 5335
    interface: 127.0.0.1
    access-control: 127.0.0.0/8 allow
    
    # Required for TLS verification
    tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt"
forward-zone:
name: "."
    # Using DoT (Port 853) instead of DoH (Port 443)
    forward-tls-upstream: yes
    forward-addr: 8.8.8.8@853#dns.google
    forward-addr: 8.8.4.4@853#dns.google

Enable unbound and restart all services

# systemctl enable unbound
# systemctl start unbound
# systemctl restart systemd-resolved
# systemctl restart NetworkManager

Test

# resolvectl query google.com
google.com: 172.253.118.138
            172.253.118.102
            172.253.118.101
            172.253.118.113
            172.253.118.139
            172.253.118.100
            2404:6800:4003:c11::8a
            2404:6800:4003:c11::71
            2404:6800:4003:c11::64
            2404:6800:4003:c11::8b


# resolvectl query duckduckgo.com
duckduckgo.com: 20.43.161.105

-- Information acquired via protocol DNS in 54.3ms.
-- Data is authenticated: no; Data was acquired via local or encrypted transport: no
-- Data from: network


Monday, January 12, 2026

Debian 13: using systemd timesync to update ntp client time

Since Debain Jessie, Debian use systemd to synchronize ntp clinet

To list timezone:

# timedatectl list-timezones | grep Jakarta
Asia/Jakarta

To set timezone:

# timedatectl set-timezone Asia/Jakarta

To show

# timedatectl 
               Local time: Mon 2026-01-12 12:44:27 WIB
           Universal time: Mon 2026-01-12 05:44:27 UTC
                 RTC time: Mon 2026-01-12 05:44:27
                Time zone: Asia/Jakarta (WIB, +0700)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Edit /etc/systemd/timesyncd.conf

...
[Time]
#NTP=
NTP=0.id.pool.ntp.org 1.id.pool.ntp.org 2.id.pool.ntp.org 2.id.pool.ntp.org 3.id.pool.ntp.org
#FallbackNTP=0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org
...

To restart service

# systemctl restart systemd-timesyncd

you can use old way using ntp client, but you need to remove this package

# timedatectl set-ntp false

Now you can install ntp and edit configuration /etc/ntp.conf.

 

 

Wednesday, January 7, 2026

Java: using build tool gradle wrapper to setup project and run

 

  • java application openjdk 17
  • gradle 8.7

install gradle 

# apt-get install gradle 

create folder project example

$ mkdir example
$ cd example

create init project

wrap gradle version for your project 

$ gradle wrapper --gradle-version 8.7
openjdk version "17.0.16" 2025-07-15
OpenJDK Runtime Environment (build 17.0.16+8-Debian-1deb12u1)
OpenJDK 64-Bit Server VM (build 17.0.16+8-Debian-1deb12u1, mixed mode, sharing)

init using gradle 8.7  debian 13 uses old 4.4 

$ ./gradlew init \
  --type java-application \
  --dsl groovy \
  --test-framework junit-jupiter \
  --package com.dedetok \
  --project-name example
openjdk version "17.0.16" 2025-07-15
OpenJDK Runtime Environment (build 17.0.16+8-Debian-1deb12u1)
OpenJDK 64-Bit Server VM (build 17.0.16+8-Debian-1deb12u1, mixed mode, sharing)
Downloading https://services.gradle.org/distributions/gradle-8.7-bin.zip
...............................................................................................................................
Unzipping ~/.gradle/wrapper/dists/gradle-8.7-bin/bhs2wmbdwecv87pi65oeuq5iu/gradle-8.7-bin.zip to ~/.gradle/wrapper/dists/gradle-8.7-bin/bhs2wmbdwecv87pi65oeuq5iu
Set executable permissions for: ~/.gradle/wrapper/dists/gradle-8.7-bin/bhs2wmbdwecv87pi65oeuq5iu/gradle-8.7/bin/gradle

Welcome to Gradle 8.7!

Here are the highlights of this release:
 - Compiling and testing with Java 22
 - Cacheable Groovy script compilation
 - New methods in lazy collection properties

For more details see https://docs.gradle.org/8.7/release-notes.html

Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details

Enter target Java version (min: 7, default: 21): 17

Select application structure:
  1: Single application project
  2: Application and library project
Enter selection (default: Single application project) [1..2] 1

Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] no


> Task :init
To learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.7/samples/sample_building_java_applications_multi_project.html

BUILD SUCCESSFUL in 5m 12s
1 actionable task: 1 executed

./settings.gradle

plugins {
    // Apply the foojay-resolver plugin to allow automatic download of JDKs
    id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
}

rootProject.name = 'example'
include('app')

./app/build.gradle

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation libs.junit.jupiter

    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

    // This dependency is used by the application.
    implementation libs.guava
}

// Apply a specific Java toolchain to ease working on different environments.
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

application {
    // Define the main class for the application.
    mainClass = 'com.dedetok.App'
}

tasks.named('test') {
    // Use JUnit Platform for unit tests.
    useJUnitPlatform()
}

./gradle/libs.versions.toml

[versions]
guava = "32.1.3-jre"
junit-jupiter = "5.10.1"

[libraries]
guava = { module = "com.google.guava:guava", version.ref = "guava" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }

To show current gradle version

$ ./gradlew --version

------------------------------------------------------------
Gradle 8.7
------------------------------------------------------------

Build time:   2024-03-22 15:52:46 UTC
Revision:     650af14d7653aa949fce5e886e685efc9cf97c10

Kotlin:       1.9.22
Groovy:       3.0.17
Ant:          Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM:          17.0.16 (Debian 17.0.16+8-Debian-1deb12u1)
OS:           Linux 6.12.57+deb13-amd64 amd64

Test run

$ ./gradlew run
Path for java installation '/usr/lib/jvm/openjdk-17' (Common Linux Locations) does not contain a java executable

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 473ms
2 actionable tasks: 1 executed, 1 up-to-date

or you can run using style $ ./gradlew :app:run

Now add maridb jcoonect into project, using Traditional Groovy Approach. edit ./app/build.gradle

...
dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation libs.junit.jupiter

    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

    // This dependency is used by the application.
    implementation libs.guava

    // mariadb jconnector (single file no need change libs.versions.toml
    implementation 'org.mariadb.jdbc:mariadb-java-client:3.3.3'

    // using libs.versions.toml must editing this file 
    //implementation libs.mariadb.client

}
...

If you wish to useing Version Catalog Approach, use 2nd option for ./app/build.gradle and edit libs.version.toml

[versions]
guava = "32.1.3-jre"
junit-jupiter = "5.10.1"
mariadb = "3.3.3"

[libraries]
guava = { module = "com.google.guava:guava", version.ref = "guava" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
mariadb-client = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version.ref = "mariadb" }

use Version Catalog Approach for complex project and involving multiple developers.

Edit ./app/src/main/java/com/dedetok/App.java

/*
 * This source file was generated by the Gradle 'init' task
 */
package com.dedetok;

import java.sql.*;

public class App {
    public String getGreeting() {
        return "Hello World!";
    }

    public static void main(String[] args) throws SQLException {
        System.out.println(new App().getGreeting());
        
        String dbUrl = "jdbc:mariadb://localhost:3306/mydatabase";
        String dbUName = "myuname";
        String dbPass = "mypass";
        
        Connection conn = DriverManager.getConnection(dbUrl, dbUName, dbPass);

    }
}

To generate single file jar for your project, edit  ./app/build.gradle

...
jar {
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE

    // change with yours
    manifest {
        attributes "Main-Class": "com.dedetok.App"
    }

    from {
        configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
}
...

You can run directly using java command

$ ./gradlew build
...
$ java -jar ./app/build/libs/app.jar
Hello World!

Your jar file location is ./app/build/libs/

Now you can edit  ./app/src/main/java/com/dedetok/App.java finish your project. Use any text editor if you wish.

Tuesday, January 6, 2026

Debian 13: bash to clean up unused gradle in folder $HOME/.gradle

stop any gradle daemon (better run this after you start your Debian)

copy paste this bash and change permission to execute

#!/bin/bash

# Set the cutoff date yyyy-mm-dd
CUTOFF_DATE="2025-08-01"

# Gradle folder
GRADLE_DIR="$HOME/.gradle"

# List of folders to clean
FOLDERS=("android" "build-scan-data" "caches" "daemon" "kotilin-profile" "native" "notifications" "undefined-build" "wrapper" ".tmp")

# 1. Stop Gradle Daemons first so files aren't locked
if [ -f "$GRADLE_DIR/daemon" ]; then
    echo "Stopping Gradle daemons..."
    gradle --stop 2>/dev/null || ./gradlew --stop 2>/dev/null
fi

echo "Cleaning Gradle folders in $GRADLE_DIR modified before $CUTOFF_DATE..."

for folder in "${FOLDERS[@]}"; do
    TARGET="$GRADLE_DIR/$folder"
    if [ -d "$TARGET" ]; then
        echo "Processing $TARGET..."
        # Find and delete files modified before the cutoff date
        find "$TARGET" -type f ! -newermt "$CUTOFF_DATE" -print -delete
        # Remove empty directories
        find "$TARGET" -type d -empty -print -delete
    else
        echo "Folder $TARGET does not exist, skipping."
    fi
done

echo "Cleanup complete."

Note:

  • change CUTOFF_DATE for any desire date
  • add or remove FOLDERS depends on your folder structure 

Wednesday, December 10, 2025

Debian 13: rebuilding nvidia driver after kernel upgrade from linux-image

After you upgrade kernel, in my case linux-image-6.12.31-amd64 to linux-image-6.12.57+deb13-amd64, you need to rebuild nvidia driver. During boot, Debian will show some error loading nvidia module

To check which module fail during boot 

# journalctl -b -u systemd-modules-load.service 
Dec 10 09:48:02 mylocalpc systemd-modules-load[781]: modprobe: ERROR: Error running install command 'modprobe n> 
Dec 10 09:48:02 mylocalpc systemd-modules-load[781]: modprobe: ERROR: could not insert 'nvidia_modeset': Invali> 
Dec 10 09:48:02 mylocalpc systemd-modules-load[789]: modprobe: FATAL: Module nvidia-current-drm not found in di> 
Dec 10 09:48:02 mylocalpc systemd-modules-load[767]: Error running install command 'modprobe nvidia-modeset ; m> 
Dec 10 09:48:02 mylocalpc systemd-modules-load[767]: Failed to insert module 'nvidia_drm': Invalid argument 
Dec 10 09:48:02 mylocalpc systemd[1]: systemd-modules-load.service: Main process exited, code=exited, status=1/> 
Dec 10 09:48:02 mylocalpc systemd[1]: systemd-modules-load.service: Failed with result 'exit-code'. 
Dec 10 09:48:02 mylocalpc systemd[1]: Failed to start systemd-modules-load.service - Load 

To install dkms

root@mylocalpc:~# apt install dkms
dkms is already the newest version (3.2.2-1~deb13u1).
dkms set to manually installed.
Summary:
  Upgrading: 0, Installing: 0, Removing: 0, Not Upgrading: 1

To show dkms status

root@mylocalpc:~# dkms status
nvidia-current/550.163.01, 6.12.31-amd64, x86_64: installed 

To rebuild nvidia driver, it will build any kernel installed.

root@mylocalpc:~# dkms install nvidia-current/550.163.01
Sign command: /lib/modules/6.12.57+deb13-amd64/build/scripts/sign-file
Signing key: /var/lib/dkms/mok.key
Public certificate (MOK): /var/lib/dkms/mok.pub

Building module(s)................ done.
Signing module /var/lib/dkms/nvidia-current/550.163.01/build/nvidia.ko
Signing module /var/lib/dkms/nvidia-current/550.163.01/build/nvidia-modeset.ko
Signing module /var/lib/dkms/nvidia-current/550.163.01/build/nvidia-drm.ko
Signing module /var/lib/dkms/nvidia-current/550.163.01/build/nvidia-uvm.ko
Signing module /var/lib/dkms/nvidia-current/550.163.01/build/nvidia-peermem.ko
Installing /lib/modules/6.12.57+deb13-amd64/updates/dkms/nvidia-current.ko.xz
Installing /lib/modules/6.12.57+deb13-amd64/updates/dkms/nvidia-current-modeset.ko.xz
Installing /lib/modules/6.12.57+deb13-amd64/updates/dkms/nvidia-current-drm.ko.xz
Installing /lib/modules/6.12.57+deb13-amd64/updates/dkms/nvidia-current-uvm.ko.xz
Installing /lib/modules/6.12.57+deb13-amd64/updates/dkms/nvidia-current-peermem.ko.xz
Running depmod.... done.

to check status of nvidia modul

root@mylocalpc:~# dkms status
nvidia-current/550.163.01, 6.12.31-amd64, x86_64: installed
nvidia-current/550.163.01, 6.12.57+deb13-amd64, x86_64: installed

restart your debian. 

the sequences are (assume you already have dkms installed and worked properly):

# apt install  linux-image-6.12.74+deb13+1-amd64
...
# dkms status
nvidia-current/550.163.01, 6.12.31-amd64, x86_64: installed
nvidia-current/550.163.01, 6.12.57+deb13-amd64, x86_64: installed
# dkms autoinstall
# apt install linux-headers-6.12.74+deb13+1-amd64
...
# dkms status
nvidia-current/550.163.01, 6.12.31-amd64, x86_64: installed
nvidia-current/550.163.01, 6.12.57+deb13-amd64, x86_64: installed
nvidia-current/550.163.01, 6.12.74+deb13+1-amd64, x86_64: installed

restart your debian to load new kernel and you may remove old linux-image

Note: dkms autoinstall will install module for existing linux-image and also remove unexisting linux-image

Friday, December 5, 2025

Pyhton3: playwright to get audio url stream

There are many tool to find url audio stream from radio station's page, here are a few list:

  1. playwright
  2. Selenium
  3. Puppeteer

To use Wget to find url audo on statik and simple web  

$ wget --spider -r -l 5 -nv -w 1 --no-clobber -A .mp3,.m3u8 "https://www.example.com/audio/stations" 2>&1 | grep -E '\.(mp3|m3u8)$' | awk '{print $3}' | sort -u > out_audio_urls.txt

Install playwright on debian with virtual environment:

myuser@mypc:~$ mkdir spider_playwright
myuser@mypc:~$ cd spider_playwright/
myuser@mypc:~/spider_playwright$ python3 -m venv venv
myuser@mypc:~/spider_playwright$ source venv/bin/activate
(venv) myuser@mypc:~/spider_playwright$ pip install playwright
Collecting playwright
  Downloading playwright-1.56.0-py3-none-manylinux1_x86_64.whl.metadata (3.5 kB)
Collecting pyee<14,>=13 (from playwright)
  Downloading pyee-13.0.0-py3-none-any.whl.metadata (2.9 kB)
Collecting greenlet<4.0.0,>=3.1.1 (from playwright)
  Using cached greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.metadata (4.1 kB)
Collecting typing-extensions (from pyee<14,>=13->playwright)
  Using cached typing_extensions-4.15.0-py3-none-any.whl.metadata (3.3 kB)
Downloading playwright-1.56.0-py3-none-manylinux1_x86_64.whl (46.3 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 46.3/46.3 MB 2.5 MB/s eta 0:00:00
Using cached greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (610 kB)
Downloading pyee-13.0.0-py3-none-any.whl (15 kB)
Using cached typing_extensions-4.15.0-py3-none-any.whl (44 kB)
Installing collected packages: typing-extensions, greenlet, pyee, playwright
Successfully installed greenlet-3.2.4 playwright-1.56.0 pyee-13.0.0 typing-extensions-4.15.0
(venv) myuser@mypc:~/spider_playwright$ playwright install
Downloading Chromium 141.0.7390.37 (playwright build v1194) from https://cdn.playwright.dev/dbazure/download/playwright/builds/chromium/1194/chromium-linux.zip
173.9 MiB [====================] 100% 0.0s
Chromium 141.0.7390.37 (playwright build v1194) downloaded to /home/myuser/.cache/ms-playwright/chromium-1194
Downloading Chromium Headless Shell 141.0.7390.37 (playwright build v1194) from https://cdn.playwright.dev/dbazure/download/playwright/builds/chromium/1194/chromium-headless-shell-linux.zip
104.3 MiB [====================] 100% 0.0s
Chromium Headless Shell 141.0.7390.37 (playwright build v1194) downloaded to /home/myuser/.cache/ms-playwright/chromium_headless_shell-1194
Downloading Firefox 142.0.1 (playwright build v1495) from https://cdn.playwright.dev/dbazure/download/playwright/builds/firefox/1495/firefox-debian-13.zip
96.7 MiB [====================] 100% 0.0s
Firefox 142.0.1 (playwright build v1495) downloaded to /home/myuser/.cache/ms-playwright/firefox-1495
Downloading Webkit 26.0 (playwright build v2215) from https://cdn.playwright.dev/dbazure/download/playwright/builds/webkit/2215/webkit-debian-13.zip
88.1 MiB [====================] 100% 0.0s
Webkit 26.0 (playwright build v2215) downloaded to /home/myuser/.cache/ms-playwright/webkit-2215
Downloading FFMPEG playwright build v1011 from https://cdn.playwright.dev/dbazure/download/playwright/builds/ffmpeg/1011/ffmpeg-linux.zip
2.3 MiB [====================] 100% 0.0s
FFMPEG playwright build v1011 downloaded to /home/myuser/.cache/ms-playwright/ffmpeg-1011

create file myspider.py and customize to your requirements, make it executable

(venv) myuser@mypc:~/spider_playwright$ chmod u+x myspider.py 

source code myspider.py modify it to meet your requirements 

import asyncio
from playwright.async_api import async_playwright

# generated and adjust by chatgpt.com

AUDIO_HINTS = [
    ".mp3", ".aac", ".m3u8", ".ogg", ".opus", ".wav",
    "stream", "/proxy/", "/live", "radio"
]

async def scan_audio_stream(url: str, listen_seconds: int = 15):
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False)
        page = await browser.new_page()

        # ----- Detect manual browser close -----
        browser_disconnected = asyncio.Event()

        def on_browser_disconnect():
            print("\n[BROWSER CLOSED] Exiting application.")
            browser_disconnected.set()

        browser.on("disconnected", on_browser_disconnect)
        # ---------------------------------------

        found = set()

        async def on_response(res):
            u = res.url.lower()
            ct = res.headers.get("content-type", "").lower()

            if "audio" in ct or any(k in u for k in AUDIO_HINTS):
                if u not in found:
                    print(f"[NEW AUDIO STREAM] {u}")
                    found.add(u)

        page.on("response", on_response)

        print("Opening page...")
        await page.goto(url, wait_until="domcontentloaded")
        await asyncio.sleep(2)

        # ---- Find audio player iframe ----
        candidate_frames = [
            f for f in page.frames
            if any(kw in f.url.lower() for kw in ["player", "radio", "embed"])
        ]
        if not candidate_frames:
            candidate_frames = page.frames  # fallback

        print("Attempting to click play...")
        for f in candidate_frames:
            try:
                for sel in ["button[aria-label='Play']", "button.play", ".jp-play", "button"]:
                    btn = await f.query_selector(sel)
                    if btn:
                        print(f"Clicked play in iframe → {f.url}")
                        await btn.click()
                        break
            except:
                pass

        print(f"\nListening for audio streams up to {listen_seconds} seconds...\n")

        # ----- Wait for 15 seconds OR browser close -----
        try:
            await asyncio.wait_for(browser_disconnected.wait(), timeout=listen_seconds)
        except asyncio.TimeoutError:
            print("\n[TIMEOUT] Done scanning.")
        # -------------------------------------------------

        await browser.close()
        return list(found)


if __name__ == "__main__":
    results = asyncio.run(scan_audio_stream(
        "https://www.example.com", # CHANGE HERE
        listen_seconds=15     # ← Fast scan
    ))

    print("\n===== ALL STREAMS FOUND =====")
    for s in results:
        print(s)

Code

from playwright.sync_api import sync_playwright

def main():
    with sync_playwright() as p:
        browser = p.chromium.launch(
            headless=False   # <-- You can manually interact
        )
        context = browser.new_context()
        page = context.new_page()

        print("🚀 Browser launched. Type the radio station URL manually.")
        print("👉 When you press Play, audio stream URLs will appear here.\n")

        # Capture outgoing requests
        def on_request(request):
            url = request.url

            if (
                ".mp3" in url or
                ".aac" in url or
                ".m3u8" in url or
                ".ogg" in url or
                "stream" in url.lower() or
                request.resource_type == "media"
            ):
                print("🎧 AUDIO STREAM REQUEST FOUND:")
                print(url, "\n")

        page.on("request", on_request)

        # Capture responses containing audio
        def on_response(response):
            url = response.url
            headers = response.headers
            content_type = headers.get("content-type", "")

            if any(fmt in content_type for fmt in ["audio", "mpeg", "aac", "ogg"]):
                print("🎧 AUDIO STREAM RESPONSE FOUND:")
                print(url, "\n")

        page.on("response", on_response)

        # Open a blank page — you will type the URL manually
        page.goto("about:blank")

        # Keep browser open
        browser.wait_for_event("disconnected")


if __name__ == "__main__":
    main()

Enjoy

Wednesday, December 3, 2025

Debian 13: bash script to show nvme/ssd healthy and cpu temperature

Requirement

  1. smartmontools
  2. lm-sensors
  3. psensor 

Installation

# apt-get install smartmontools lm-sensors psensor

copy paste this script to show general temperature on nvme/ssd and cpu. It also give information about nvme/ssd healthy.

#!/bin/bash
# this code generated by chatgpt.com no sign in
# each step was interactive, output from pc will be feed to chatgpt to generate correct output

DRIVE=${1:-/dev/sda}

echo "=== SMART Drive Information ($DRIVE) ==="

sudo smartctl -H -A "$DRIVE" | awk '
/^SMART overall-health/      {print "Drive Health: " $NF}
/^194 Temperature_Celsius/   {print "Drive Temperature: " $10 "°C"}
/^190 Airflow_Temperature/   {print "Drive Temperature: " $10 "°C"}
'

echo
echo "=== CPU Temperature ==="
sensors | awk '
/k10temp/ {found=1}
/temp1:/ && found {print "CPU Temp:", $2; found=0}
'

echo
echo "=== GPU Temperature (AMDGPU) ==="
sensors | awk '
/amdgpu/ {found=1}
/edge:/ && found {print "GPU Temp:", $2; found=0}
'

echo
echo "=== ACPI Temperatures ==="
sensors | awk '
/acpitz/ {block=1}
/temp/ && block {print "ACPI " $1, $2}
/^\s*$/ {block=0}
'

Change permission

# chmod u+x ./checkme.sh

Run as sudo or root