[{"content":"Instead of reformatting USB for each new image, Ventoy lets you simply copy ISO files like regular files. At boot, you get a menu with all available images.\nBenefits:\n✅ No need to rewrite USB for each image ✅ Support for Windows, Linux, utilities - all on one drive ✅ Regular files accessible from any OS ✅ Flexible configuration via JSON 🗂 Correct USB Structure [First USB partition - exFAT/NTFS] ├── /ventoy/ # ← Must be here! │ ├── ventoy.json # Main config │ ├── revi/ # Windows auto-install │ │ └── autounattend.xml │ └── theme/ # Custom theme │ └── distro/theme.txt │ ├── BACKUP/ # Working files ├── LINUX/ # Linux ISOs │ ├── Archlinux 2025.12.01.iso │ ├── Debian 13.2.0.iso │ └── NixOS 25.11.1734.iso ├── WINDOWS/ # Windows ISOs │ ├── Windows 10 22H2.iso │ ├── Windows 10 Enterprise LTSC 2021.iso │ └── Windows 11 25H2.iso ├── ReviSetup/ # Post-install scripts │ └── setup.cmd └── UTILS/ # Utilities ├── gparted-live.iso └── memtest86+.iso ⚠️ Critical: /ventoy/ must be on the first partition (where ISOs are), NOT in root!\n⚙️ Basic Configuration: ventoy.json File must be at /ventoy/ventoy.json, UTF-8 encoding.\nMinimal Example { \u0026#34;control\u0026#34;: [ { \u0026#34;VTOY_DEFAULT_MENU_MODE\u0026#34;: \u0026#34;1\u0026#34; }, { \u0026#34;VTOY_FILT_DOT_UNDERSCORE_FILE\u0026#34;: \u0026#34;1\u0026#34; } ], \u0026#34;theme\u0026#34;: { \u0026#34;file\u0026#34;: \u0026#34;/ventoy/theme/distro/theme.txt\u0026#34;, \u0026#34;gfxmode\u0026#34;: \u0026#34;1920x1080\u0026#34;, \u0026#34;resolution_fit\u0026#34;: \u0026#34;1\u0026#34; } } Parameter Description VTOY_DEFAULT_MENU_MODE Default menu mode VTOY_FILT_DOT_UNDERSCORE_FILE Hide files starting with . and _ theme.file Path to GRUB theme file gfxmode Menu resolution resolution_fit Auto-fit to screen 🎨 Customization: Menu Themes Where to Get Themes distro-grub-themes - collection of ready-made themes Gnome-look.org - themes tagged ventoy Create your own - follow Ventoy documentation Installing a Theme # Clone theme cd /mnt/ventoy/ventoy/theme git clone https://github.com/AdisonCavani/distro-grub-themes.git distro # Or download from Gnome-look wget https://www.gnome-look.org/.../theme.tar.gz tar xzf theme.tar.gz In ventoy.json specify path:\n{ \u0026#34;theme\u0026#34;: { \u0026#34;file\u0026#34;: \u0026#34;/ventoy/theme/distro/theme.txt\u0026#34;, \u0026#34;resolution_fit\u0026#34;: \u0026#34;1\u0026#34; } } 🪟 Windows Auto-Install Structure for Auto-Install /ventoy/ └── revi/ └── autounattend.xml # Windows Setup的 answers /ReviSetup/ └── setup.cmd # Post-install Example ventoy.json for Auto-Install { \u0026#34;auto_install\u0026#34;: [ { \u0026#34;parent\u0026#34;: \u0026#34;/WINDOWS\u0026#34;, \u0026#34;template\u0026#34;: [\u0026#34;/ventoy/revi/autounattend.xml\u0026#34;], \u0026#34;autosel\u0026#34;: 1 } ] } Parameter Value parent Folder with Windows images template Path to autounattend.xml autosel Auto-select template What autounattend.xml Does Skips Microsoft account creation Disables telemetry Applies privacy settings Runs setup.cmd after install 💡 Ready-made configs: meetrevision/ventoy-conf\n🛠 Post-Install: setup.cmd Script runs automatically after Windows installation.\nExample Actions :: Disable driver updates reg add \u0026#34;HKLM\\Software\\Policies\\Microsoft\\Windows\\DriverSearching\u0026#34; /v \u0026#34;SearchOrderConfig\u0026#34; /t REG_DWORD /d 0 /f :: Pause updates until 2038 reg add \u0026#34;HKLM\\SOFTWARE\\Microsoft\\WindowsUpdate\\UX\\Settings\u0026#34; /v \u0026#34;PauseUpdatesExpiryTime\u0026#34; /t REG_SZ /d \u0026#34;2038-01-19T03:14:07Z\u0026#34; /f :: Disable telemetry reg add \u0026#34;HKLM\\Software\\Policies\\Microsoft\\Windows\\DataCollection\u0026#34; /v \u0026#34;AllowTelemetry\u0026#34; /t REG_DWORD /d 0 /f :: Prevent Teams auto-install reg add \u0026#34;HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\Windows Chat\u0026#34; /v \u0026#34;ChatIcon\u0026#34; /t REG_DWORD /d 2 /f 🗂 Checklist: Creating USB Installed Ventoy via Ventoy2Disk.sh / .exe Created /ventoy/ on first partition Placed ventoy.json in /ventoy/ (UTF-8) Copied images to logical folders (LINUX/, WINDOWS/) (Optional) Installed menu theme (Optional) Configured Windows auto-install Verified JSON syntax via json.cn Tested boot 🔧 Useful Commands # Check ventoy.json syntax cat /ventoy/ventoy.json | jq . # In Ventoy menu: F5 - show ventoy.json content # Recreate Ventoy partition (data will be lost!) sudo ./Ventoy2Disk.sh -i /dev/sdX 📚 Additional Features Ventoy supports many plugins and extensions:\nPersistence - save data between Live system reboots Memdisk - boot images into RAM Auto install - OS installation automation Custom menu - custom menu items Injection - inject drivers/files into images 🔗 Documentation: ventoy.net\n⚠️ Common Issues Symptom Solution ventoy.json not applied Check path: strictly /ventoy/ventoy.json Theme not loading Check encoding (UTF-8) and path in config Auto-install not working Ensure parent points to correct folder JSON parse error Check syntax via online validator 🔐 Security ✅ exFAT - accessible from any OS (but unencrypted) 🔐 For sensitive files: VeraCrypt container ✅ autounattend.xml and setup.cmd - plain text, no passwords 🗂 Links 🚀 Official Ventoy Site 🎨 Theme Collection 🎨 Themes on Gnome-look 🪟 Windows Auto-Install 📘 Plugin Documentation ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/linux/ventoy-multiboot/","summary":"\u003cp\u003eInstead of reformatting USB for each new image, \u003cstrong\u003eVentoy\u003c/strong\u003e lets you simply copy ISO files like regular files. At boot, you get a menu with all available images.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBenefits\u003c/strong\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e✅ No need to rewrite USB for each image\u003c/li\u003e\n\u003cli\u003e✅ Support for Windows, Linux, utilities - all on one drive\u003c/li\u003e\n\u003cli\u003e✅ Regular files accessible from any OS\u003c/li\u003e\n\u003cli\u003e✅ Flexible configuration via JSON\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"-correct-usb-structure\"\u003e🗂 Correct USB Structure\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e[First USB partition - exFAT/NTFS]\n├── /ventoy/                    # ← Must be here!\n│   ├── ventoy.json            # Main config\n│   ├── revi/                  # Windows auto-install\n│   │   └── autounattend.xml\n│   └── theme/                 # Custom theme\n│       └── distro/theme.txt\n│\n├── BACKUP/                    # Working files\n├── LINUX/                     # Linux ISOs\n│   ├── Archlinux 2025.12.01.iso\n│   ├── Debian 13.2.0.iso\n│   └── NixOS 25.11.1734.iso\n├── WINDOWS/                   # Windows ISOs\n│   ├── Windows 10 22H2.iso\n│   ├── Windows 10 Enterprise LTSC 2021.iso\n│   └── Windows 11 25H2.iso\n├── ReviSetup/                 # Post-install scripts\n│   └── setup.cmd\n└── UTILS/                     # Utilities\n    ├── gparted-live.iso\n    └── memtest86+.iso\n\u003c/code\u003e\u003c/pre\u003e\u003cblockquote\u003e\n\u003cp\u003e⚠️ \u003cstrong\u003eCritical\u003c/strong\u003e: \u003ccode\u003e/ventoy/\u003c/code\u003e must be on the \u003cstrong\u003efirst partition\u003c/strong\u003e (where ISOs are), NOT in root!\u003c/p\u003e","title":"Ventoy: Multi-Boot USB with Correct Structure"},{"content":" 📌 This is Part 3 of the series. Part 1: Theory, Part 2: Practice.\n🔗 What We\u0026rsquo;re Integrating Component Purpose Difficulty ONEmesh MQTT Bridge between local mesh and global map + Telegram notifications 🟢 Low Home Assistant Node sensors, device_tracker, automations on mesh messages 🟡 Medium Notifications Alerts for new nodes, lost connection, mentions in chat 🟢 Low 💡 All examples tested on: HA 2026.4.2 (Docker) + Orange Pi 3B + built-in MQTT broker.\n🌐 Step 1: Configure Meshtastic MQTT for ONEmesh Connection Parameters Parameter Value Note MQTT Address mqtt.onemesh.ru Community server Username onemesh Default Password onecat Shared for all Root topic msh/RU/XXX XXX = city code (list) TLS enabled Yes Try No if not working JSON enabled Yes Required for Home Assistant Uplink / Downlink Yes / No Uplink only is enough for monitoring ⚠️ Important: Firmware 2.5+ supports new encryption key format (PKI). If using encryption - ensure keys are synced across nodes.\nHow to Verify Enable JSON enabled in MQTT settings Connect to broker via mosquitto_sub or MQTT Explorer: mosquitto_sub -h mqtt.onemesh.ru -u onemesh -P onecat \\ -t \u0026#39;msh/RU/MOW/json/#\u0026#39; -v You\u0026rsquo;ll see messages like: { \u0026#34;id\u0026#34;: 452664778, \u0026#34;from\u0026#34;: 2130636288, \u0026#34;payload\u0026#34;: { \u0026#34;text\u0026#34;: \u0026#34;Hello from local mesh!\u0026#34;, \u0026#34;battery_level\u0026#34;: 87, \u0026#34;voltage\u0026#34;: 4.12 }, \u0026#34;type\u0026#34;: \u0026#34;text\u0026#34;, \u0026#34;timestamp\u0026#34;: 1714234567 } 📬 Step 2: Telegram Notifications via ONEmesh Bot ONEmesh automatically forwards messages from your city topic to a private chat with the bot.\nNotification Examples [26.04.2026 20:52] ONEmesh Bot: LF | qwrt (https://map.onemesh.ru/?node_id=483535916) QWRT Pocket 20, standard. but for home node - triad antenna SNR 4.75 RSSI -92 HopLimit 3 - data from 44b4 (https://map.onemesh.ru/?node_id=49169588) Field Meaning Why it matters SNR Signal-to-Noise Ratio Signal quality: higher = better RSSI Received Signal Strength Signal power: closer to 0 = better HopLimit Remaining hops Shows how far message traveled Setup Find @ONEmeshBot in Telegram Send /start - bot will show instructions Ensure your node sends data to MQTT with correct root topic Done: notifications will arrive automatically 💡 Tip: if no notifications - check that OK to MQTT is enabled in channel settings and node has internet.\n🏠 Step 3: Home Assistant Integration Prerequisites Built-in MQTT broker in HA (Settings → Devices \u0026amp; Services → MQTT) Meshtastic node with JSON enabled in MQTT Access to configuration.yaml and ability to create mqtt.yaml Step 3.1: Connect MQTT in HA # configuration.yaml mqtt: !include mqtt.yaml # mqtt.yaml broker: core-mosquitto # or your broker address port: 1883 username: homeassistant password: !secret mqtt_password # For external broker (e.g., ONEmesh): # broker: mqtt.onemesh.ru # port: 8883 # username: onemesh # password: onecat # certificate: /config/certs/ca.crt # for TLS Step 3.2: Create Sensors for Node # mqtt.yaml - continued sensor: # Node battery - name: \u0026#34;Meshtastic Node Battery\u0026#34; unique_id: \u0026#34;meshtastic_node_battery\u0026#34; state_topic: \u0026#34;msh/RU/MOW/json/LongFast/!abcd1234\u0026#34; value_template: \u0026gt;- {% if value_json.from == 2130636288 and value_json.payload.battery_level is defined %} {{ value_json.payload.battery_level | int }} {% else %} {{ this.state }} {% endif %} unit_of_measurement: \u0026#34;%\u0026#34; device_class: battery # Voltage - name: \u0026#34;Meshtastic Node Voltage\u0026#34; unique_id: \u0026#34;meshtastic_node_voltage\u0026#34; state_topic: \u0026#34;msh/RU/MOW/json/LongFast/!abcd1234\u0026#34; value_template: \u0026gt;- {% if value_json.from == 2130636288 and value_json.payload.voltage is defined %} {{ value_json.payload.voltage | float | round(2) }} {% else %} {{ this.state }} {% endif %} unit_of_measurement: \u0026#34;V\u0026#34; device_class: voltage # Channel utilization (airtime load) - name: \u0026#34;Meshtastic Channel Utilization\u0026#34; unique_id: \u0026#34;meshtastic_chutil\u0026#34; state_topic: \u0026#34;msh/RU/MOW/json/LongFast/!abcd1234\u0026#34; value_template: \u0026gt;- {% if value_json.from == 2130636288 and value_json.payload.channel_utilization is defined %} {{ value_json.payload.channel_utilization | float | round(1) }} {% else %} {{ this.state }} {% endif %} unit_of_measurement: \u0026#34;%\u0026#34; 🔑 Important: replace 2130636288 with your node\u0026rsquo;s decimal from (find via MQTT Explorer or meshtastic --info).\nStep 3.3: Location Tracking (device_tracker) # automations.yaml - alias: \u0026#34;Meshtastic: Update node location\u0026#34; trigger: platform: mqtt topic: \u0026#34;msh/RU/MOW/json/LongFast/!abcd1234\u0026#34; value_template: \u0026gt;- {% if value_json.from == 2130636288 and value_json.payload.latitude_i is defined and value_json.payload.longitude_i is defined %}on{% endif %} action: service: device_tracker.see data: dev_id: \u0026#34;meshtastic_node_1\u0026#34; gps: - \u0026#34;{{ (trigger.payload_json.payload.latitude_i | int * 1e-7) }}\u0026#34; - \u0026#34;{{ (trigger.payload_json.payload.longitude_i | int * 1e-7) }}\u0026#34; battery: \u0026#34;{{ states(\u0026#39;sensor.meshtastic_node_battery\u0026#39;) | default(0) }}\u0026#34; 💡 Meshtastic stores coordinates as integer * 1e7, so multiply by 1e-7 to get real values.\nStep 3.4: Notifications on Chat Mentions # automations.yaml - alias: \u0026#34;Meshtastic: Notify on mention\u0026#34; trigger: platform: mqtt topic: \u0026#34;msh/RU/MOW/json/LongFast/!abcd1234\u0026#34; value_template: \u0026gt;- {% if value_json.type == \u0026#34;text\u0026#34; and value_json.payload.text is defined and \u0026#34;ponf\u0026#34; in value_json.payload.text.lower() %}on{% endif %} action: service: notify.mobile_app_your_phone data: title: \u0026#34;📡 Meshtastic\u0026#34; message: \u0026#34;Mention: {{ trigger.payload_json.payload.text }}\u0026#34; data: priority: high 🔐 Security: Encryption and Keys What Changed in Firmware 2.5+ Version Key Type Notes \u0026lt; 2.5 Single PSK per channel Simple setup, but vulnerable if compromised ≥ 2.5 PKI + shared secret Separate keys for encryption and authentication How to Configure Encryption In Meshtastic app: Channel → Primary → PSK Enable encryption Copy the key (same AQ== for primary channel) In MQTT settings: Encryption enabled → Yes Ensure all nodes in mesh use the same key ⚠️ Critical: if keys don\u0026rsquo;t match - messages arrive but won\u0026rsquo;t decrypt. Verify via MQTT Explorer.\nWhere to Store Keys ✅ In secrets.yaml Home Assistant (don\u0026rsquo;t commit to Git!) ✅ In password manager (Bitwarden, KeePassXC) ❌ Not in public repos, logs, or screenshots ⚠️ Common Issues Symptom Cause Fix Sensors not updating Wrong from in value_template Find node\u0026rsquo;s decimal ID via meshtastic --info No Telegram messages Wrong root topic Check city code: msh/RU/MOW, msh/RU/SPB, etc. Encryption not working Keys don\u0026rsquo;t match Copy PSK exactly, no spaces, to both nodes device_tracker not moving Coordinates in wrong format Multiply latitude_i/longitude_i by 1e-7 HA won\u0026rsquo;t connect to broker Wrong credentials Check username/password and port (1883/8883) Links 📡 Meshtastic MQTT Docs 🏠 HA Meshtastic Integration 🗺️ ONEmesh Map 🔐 Meshtastic Security Guide ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/mesh/integrations/","summary":"\u003cblockquote\u003e\n\u003cp\u003e📌 \u003cstrong\u003eThis is Part 3 of the series\u003c/strong\u003e. \u003ca href=\"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/mesh/intro/\"\u003ePart 1: Theory\u003c/a\u003e, \u003ca href=\"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/mesh/practice/\"\u003ePart 2: Practice\u003c/a\u003e.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"-what-were-integrating\"\u003e🔗 What We\u0026rsquo;re Integrating\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eComponent\u003c/th\u003e\n          \u003cth\u003ePurpose\u003c/th\u003e\n          \u003cth\u003eDifficulty\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eONEmesh MQTT\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eBridge between local mesh and global map + Telegram notifications\u003c/td\u003e\n          \u003ctd\u003e🟢 Low\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eHome Assistant\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eNode sensors, device_tracker, automations on mesh messages\u003c/td\u003e\n          \u003ctd\u003e🟡 Medium\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eNotifications\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eAlerts for new nodes, lost connection, mentions in chat\u003c/td\u003e\n          \u003ctd\u003e🟢 Low\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 All examples tested on: HA 2026.4.2 (Docker) + Orange Pi 3B + built-in MQTT broker.\u003c/p\u003e","title":"Heltec V4: Integrations. Home Assistant, Telegram, Monitoring. Part 3"},{"content":"Home Assistant in Docker doesn\u0026rsquo;t see Bluetooth devices, even if everything works on the host.\nCauses:\n❌ Container has no direct access to /dev/hci0 ❌ BlueZ inside container conflicts with host daemon ❌ Passive BLE scanning requires --experimental flag in BlueZ Solution: Don\u0026rsquo;t run Bluetooth stack inside container - passthrough D-Bus from host instead.\n✅ Docker Compose Configuration Minimal Setup services: home-assistant: container_name: home-assistant image: ghcr.io/home-assistant/home-assistant:stable volumes: - config:/config - /run/dbus:/run/dbus:ro # ← Critical for Bluetooth cap_add: - NET_ADMIN - NET_RAW - SYS_ADMIN restart: unless-stopped networks: - traefik - prometheus volumes: config: driver: local networks: traefik: external: true name: traefik prometheus: external: true name: prometheus ⚠️ Don\u0026rsquo;t add devices: - /dev/hci0:/dev/hci0 - not needed with D-Bus passthrough and may cause conflicts.\n🔧 BlueZ Configuration on Host Enabling Experimental Mode (for Passive Scanning) Home Assistant uses passive BLE scanning, which requires running bluetoothd with --experimental flag.\n# 1. Create systemd override sudo systemctl edit bluetooth # 2. Insert: [Service] ExecStart= ExecStart=/usr/lib/bluetooth/bluetoothd --experimental # 3. Apply and restart sudo systemctl daemon-reload sudo systemctl restart bluetooth # 4. Verify flag is applied ps aux | grep bluetoothd # Expected: /usr/lib/bluetooth/bluetoothd --experimental 💡 Why this is needed: Passive scanning doesn\u0026rsquo;t send active requests, saving device battery. But this feature in BlueZ is marked \u0026ldquo;experimental\u0026rdquo;.\n🔗 Pairing Devices (On Host Only!) Manage Bluetooth only on the host, not inside the container.\n# 1. Enable adapter sudo bluetoothctl power on # 2. Start scanning sudo bluetoothctl scan on # 3. When device appears (e.g., Meshtastic_XXXX): sudo bluetoothctl pair AA:BB:CC:DD:EE:FF sudo bluetoothctl trust AA:BB:CC:DD:EE:FF sudo bluetoothctl connect AA:BB:CC:DD:EE:FF ✅ After pairing on host, Home Assistant will see the device via passthrough D-Bus.\n⚙️ Integration in Home Assistant Installing Integration Install Meshtastic via HACS (or other needed integration) Restart HA: docker compose restart home-assistant Settings → Integrations → Add Integration → [Name] Device should appear in discovered list (by name or address) If Device Not Discovered # Check on host: - Device paired? `bluetoothctl paired-devices` - Adapter not blocked? `rfkill list` - BlueZ running with --experimental? `ps aux | grep bluetoothd` # In Home Assistant: - Reload integration: Settings → System → Reload - Check logs: Settings → System → Logs → search \u0026#34;bluetooth\u0026#34; ⚠️ Common Issues Symptom Cause Solution Unable to open mgmt_socket in container Daemon conflict Don\u0026rsquo;t run bluetoothctl inside container Device not appearing in scan Pairing mode not enabled on device Enable pairing mode in device app Error.Busy on power on hciattach holding device Remove -n flag in init service Passive scanning not working BlueZ without --experimental Add flag to ExecStart and restart Links 🏠 Home Assistant Bluetooth Docs 📘 BlueZ Experimental Features 🐙 Meshtastic HA Integration 🐳 Docker Bind Mounts ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/home-assistant/bluetooth-docker/","summary":"\u003cp\u003eHome Assistant in Docker doesn\u0026rsquo;t see Bluetooth devices, even if everything works on the host.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eCauses\u003c/strong\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e❌ Container has no direct access to \u003ccode\u003e/dev/hci0\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e❌ BlueZ inside container conflicts with host daemon\u003c/li\u003e\n\u003cli\u003e❌ Passive BLE scanning requires \u003ccode\u003e--experimental\u003c/code\u003e flag in BlueZ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eSolution\u003c/strong\u003e: Don\u0026rsquo;t run Bluetooth stack inside container - passthrough D-Bus from host instead.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"-docker-compose-configuration\"\u003e✅ Docker Compose Configuration\u003c/h2\u003e\n\u003ch3 id=\"minimal-setup\"\u003eMinimal Setup\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eservices\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003ehome-assistant\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003econtainer_name\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ehome-assistant\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eimage\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eghcr.io/home-assistant/home-assistant:stable\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003evolumes\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003econfig:/config\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003e/run/dbus:/run/dbus:ro\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c\"\u003e# ← Critical for Bluetooth\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003ecap_add\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003eNET_ADMIN\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003eNET_RAW\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003eSYS_ADMIN\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003erestart\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eunless-stopped\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003enetworks\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003etraefik\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003eprometheus\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003evolumes\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003edriver\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003elocal\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003enetworks\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003etraefik\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eexternal\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003etraefik\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eprometheus\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eexternal\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eprometheus\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e⚠️ \u003cstrong\u003eDon\u0026rsquo;t add \u003ccode\u003edevices: - /dev/hci0:/dev/hci0\u003c/code\u003e\u003c/strong\u003e - not needed with D-Bus passthrough and may cause conflicts.\u003c/p\u003e","title":"Home Assistant + Docker: Bluetooth for Device Discovery"},{"content":"On Orange Pi 3B, the built-in Bluetooth chip Spreadtrum UWE5622 is connected via UART (/dev/ttyBT0). Unlike USB adapters, it requires:\nLoading firmware and calibration data before initialization Running hciattach_opi with correct flags Correct startup order: chip initialization first, then BlueZ daemon Symptoms:\nbluetoothctl scan on → No default controller available btmgmt info → Index list with 0 items hciconfig -a shows hci0, but bluetoothctl doesn\u0026rsquo;t see it Error org.bluez.Error.Busy when trying to power on Cause: The service orangepi3b-sprd-bluetooth.service runs hciattach_opi with the -n flag (no-detach), which holds the device and prevents BlueZ from registering the controller.\n✅ Solution: Two Steps Step 1: Install Missing Utilities sudo apt update sudo apt install -y rfkill bluez rfkill is needed to unblock the adapter, bluez is the Bluetooth stack itself.\nStep 2: Fix the Initialization Service Option A: Quick Fix (Manual) # 1. Stop everything sudo systemctl stop orangepi3b-sprd-bluetooth sudo systemctl stop bluetooth sudo killall -9 hciattach_opi 2\u0026gt;/dev/null sleep 2 # 2. Load drivers and unblock adapter sudo modprobe -a sprdbt_tty sprdwl_ng sudo rfkill unblock all # 3. Run initialization WITHOUT -n flag (hciattach will detach automatically) sudo /usr/bin/hciattach_opi -s 1500000 /dev/ttyBT0 sprd # ← Process will complete in 2-3 seconds if chip responded # 4. Start BlueZ - it will pick up the ready hci0 sudo systemctl start bluetooth sleep 2 # 5. Verify btmgmt info # Expected: Index list with 1 item, hci0: Primary controller sudo bluetoothctl power on sudo bluetoothctl scan on # Expected: Changing power on succeeded, device appears in scan Option B: Permanent Fix (via systemd) # 1. Open service for editing sudo systemctl edit orangepi3b-sprd-bluetooth # 2. Override ExecStart (remove -n): [Service] ExecStart= ExecStart=/usr/bin/hciattach_opi -s 1500000 /dev/ttyBT0 sprd # 3. Apply and restart sudo systemctl daemon-reload sudo systemctl restart orangepi3b-sprd-bluetooth sudo systemctl restart bluetooth # 4. Verify btmgmt info sudo bluetoothctl power on sudo bluetoothctl scan on 💡 Why -n breaks things: The no-detach flag keeps hciattach running in the background and holding the UART. BlueZ can\u0026rsquo;t register the controller because the device is already busy.\n🔧 If It Doesn\u0026rsquo;t Work: Diagnostics # Check if kernel sees the chip dmesg | grep -iE \u0026#34;ttyBT|sprd|uwe5622\u0026#34; # Check if drivers are loaded lsmod | grep -iE \u0026#34;sprd|bt\u0026#34; # Check for blocks rfkill list # If Soft blocked: yes → sudo rfkill unblock bluetooth # Check if bluetoothd is running with required flags ps aux | grep bluetoothd # For passive scanning (required for HA): needs --experimental # Check device permissions ls -l /dev/hci0 /dev/ttyBT0 # Should be: root:bluetooth, permissions 660 🐳 For Docker: Passing Through to Container If you\u0026rsquo;re running Home Assistant or another app in Docker:\nservices: home-assistant: volumes: - /run/dbus:/run/dbus:ro # ← Required for Bluetooth access # Don\u0026#39;t run bluetoothctl inside the container! # Manage pairing on the host, the app will pick it up via D-Bus ⚠️ Don\u0026rsquo;t use network_mode: host just for Bluetooth - it breaks network isolation. Mounting /run/dbus is enough.\nLinks 🍊 Orange Pi 3B Wiki 📘 BlueZ Documentation 🔧 hciattach Source 🐙 Meshtastic Docs ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/linux/orangepi/orangepi3b-bluetooth/","summary":"\u003cp\u003eOn Orange Pi 3B, the built-in Bluetooth chip \u003cstrong\u003eSpreadtrum UWE5622\u003c/strong\u003e is connected via UART (\u003ccode\u003e/dev/ttyBT0\u003c/code\u003e). Unlike USB adapters, it requires:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eLoading firmware and calibration data before initialization\u003c/li\u003e\n\u003cli\u003eRunning \u003ccode\u003ehciattach_opi\u003c/code\u003e with correct flags\u003c/li\u003e\n\u003cli\u003eCorrect startup order: chip initialization first, then BlueZ daemon\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eSymptoms\u003c/strong\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ebluetoothctl scan on\u003c/code\u003e → \u003ccode\u003eNo default controller available\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebtmgmt info\u003c/code\u003e → \u003ccode\u003eIndex list with 0 items\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ehciconfig -a\u003c/code\u003e shows \u003ccode\u003ehci0\u003c/code\u003e, but \u003ccode\u003ebluetoothctl\u003c/code\u003e doesn\u0026rsquo;t see it\u003c/li\u003e\n\u003cli\u003eError \u003ccode\u003eorg.bluez.Error.Busy\u003c/code\u003e when trying to power on\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eCause\u003c/strong\u003e: The service \u003ccode\u003eorangepi3b-sprd-bluetooth.service\u003c/code\u003e runs \u003ccode\u003ehciattach_opi\u003c/code\u003e with the \u003ccode\u003e-n\u003c/code\u003e flag (no-detach), which holds the device and prevents BlueZ from registering the controller.\u003c/p\u003e","title":"Orange Pi 3B: Enabling Bluetooth (Spreadtrum UWE5622)"},{"content":"The home zone (zone.home) is the foundation for:\n✅ Presence detection (automations for \u0026ldquo;arrived/left\u0026rdquo;) ✅ Sunrise/sunset calculation (lighting, blinds) ✅ Weather forecasting (coordinate-based) ✅ Geofencing for devices and users Inaccurate coordinates = false triggers, wrong forecasts, broken automations.\n🎯 The Default Wizard Problem During initial setup, Home Assistant asks to pick a location on a map. But:\n❌ No manual coordinate input in the wizard ❌ IP-based auto-detection often has 1–10 km error ❌ Elevation above sea level is not requested Solution: configure precise coordinates after installation, via UI or YAML.\n🔧 Method 1: Via UI (After Installation) Step 1: Get Precise Coordinates Use a GPS-enabled device (phone with Home Assistant app):\nInstall the official companion app Grant precise location permission Enable device_tracker.\u0026lt;device\u0026gt; sensor in app settings Open Developer Tools → States in web UI Find entity device_tracker.\u0026lt;your_device\u0026gt; Copy attributes: latitude, longitude, altitude Step 2: Update Home Zone Settings → Areas, labels \u0026amp; zones → Zones Open home Paste coordinates into Latitude / Longitude fields Save Step 3: Set Elevation Settings → System → General Fill Elevation above sea level (in meters) Save 💡 Zone radius: default is 100 m. Increase to 200–500 m for rural areas or if GPS has noticeable error.\n⚙️ Method 2: Via YAML (Advanced) Add to configuration.yaml:\nhomeassistant: name: Home latitude: 55.7558 # ← example, replace with yours longitude: 37.6173 # ← example, replace with yours elevation: 156 # elevation in meters radius: 200 # zone radius in meters unit_system: metric time_zone: \u0026#34;Europe/Moscow\u0026#34; country: \u0026#34;RU\u0026#34; currency: \u0026#34;RUB\u0026#34; Important:\nAfter changing configuration.yaml, run Check Configuration and Restart If coordinates are set in YAML, UI fields become read-only 🔄 Alternative: homeassistant.set_location Action For dynamic updates (e.g., from automation):\nautomation: - alias: \u0026#34;Update home location\u0026#34; trigger: platform: time_pattern minutes: \u0026#34;/30\u0026#34; # every 30 minutes action: - action: homeassistant.set_location data: latitude: \u0026#34;{{ states(\u0026#39;sensor.gps_latitude\u0026#39;) }}\u0026#34; longitude: \u0026#34;{{ states(\u0026#39;sensor.gps_longitude\u0026#39;) }}\u0026#34; elevation: \u0026#34;{{ states(\u0026#39;sensor.gps_altitude\u0026#39;) }}\u0026#34; ⚠️ Use with caution: frequent location updates may break presence automations.\n⚠️ Common Issues # \u0026#34;Away\u0026#34; doesn\u0026#39;t change to \u0026#34;Home\u0026#34; on return → Check zone radius: increase to 300–500 m → Ensure `device_tracker` is updating (interval, min distance) # Wrong sunrise/sunset time → Verify `elevation` and `time_zone` in settings → Reload `sun` integration # Coordinates won\u0026#39;t save in UI → They may be set in `configuration.yaml` - edit only there Links 🏠 Home Assistant Location Docs 📍 Zone Configuration 📱 Companion App Location Tracking 🗺️ Get Coordinates (OpenStreetMap) ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/home-assistant/location-config/","summary":"\u003cp\u003eThe home zone (\u003ccode\u003ezone.home\u003c/code\u003e) is the foundation for:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e✅ Presence detection (automations for \u0026ldquo;arrived/left\u0026rdquo;)\u003c/li\u003e\n\u003cli\u003e✅ Sunrise/sunset calculation (lighting, blinds)\u003c/li\u003e\n\u003cli\u003e✅ Weather forecasting (coordinate-based)\u003c/li\u003e\n\u003cli\u003e✅ Geofencing for devices and users\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eInaccurate coordinates = false triggers, wrong forecasts, broken automations.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"-the-default-wizard-problem\"\u003e🎯 The Default Wizard Problem\u003c/h2\u003e\n\u003cp\u003eDuring initial setup, Home Assistant asks to pick a location on a map. But:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e❌ No manual coordinate input in the wizard\u003c/li\u003e\n\u003cli\u003e❌ IP-based auto-detection often has 1–10 km error\u003c/li\u003e\n\u003cli\u003e❌ Elevation above sea level is not requested\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eSolution\u003c/strong\u003e: configure precise coordinates after installation, via UI or YAML.\u003c/p\u003e","title":"Home Assistant: Precise Home Location Setup"},{"content":" 📌 This is Part 2 of the series. Part 1: Theory explains why this matters.\n📦 Unboxing and Preparation Heltec V4 Contents Component Purpose Board ~60×30 mm ESP32-S3R2 + SX1262, OLED 128×64, USB-C Antenna (IPEX) Connect to ANT port - mandatory! USB-C cable Power + flashing + debugging Pins (optional) For external sensors/antennas ⚠️ Important: without antenna connected, the radio module may be damaged. Always attach antenna before powering on.\nHeltec V4 Specifications Component Description MCU ESP32-S3R2 (WiFi + Bluetooth) LoRa Transceiver Semtech SX1262 Frequencies 863–870 MHz (EU), 902–928 MHz (US) Display 0.96\u0026quot; OLED 128×64 Power Up to +28±1 dBm (High Power option) Power Supply USB-C + optimized LiPo management Connectors USB-C, U.FL/IPEX for LoRa, 1.25-8Pin GNSS, 1.25-2Pin Solar Form Factor Pin-compatible with V3/V3.1 ⚡ Flashing: Web Flasher Official flasher: https://flasher.meshtastic.org\nRequirements Requirement Why Chromium-based browser (Chrome, Edge, Brave) Web Serial API works only there Serial port access On Linux - user must be in dialout group Battery disconnected During flashing - USB power only 🐧 Linux: Serial Port Permissions If you see:\n[09:52:42.841] Serial: serial_io_handler.cc:157 Failed to open serial port: FILE_ERROR_ACCESS_DENIED Fix:\n# Add user to dialout group sudo usermod -a -G dialout $USER # Apply changes (re-login or) newgrp dialout # Verify access ls -l /dev/ttyUSB* # or /dev/ttyACM* 🔧 Flashing Process Disconnect battery and USB from the board Open web flasher, select: Device: Heltec V4 Firmware: 2.7.21 (or latest stable/beta) Variant: Full erase and install Click Erase Flash and Install Hold the PRG button on the board While holding PRG, plug in the USB cable Observe: brief red flash → USB JTAG appears in port dropdown Release PRG, select USB JTAG, click Connect Wait for flashing to complete (terminal shows progress) After Leaving... message, press the RST button (reset) 💡 If flasher doesn\u0026rsquo;t detect the port - try another cable (not all support data), another USB port, or restart the browser.\n🔌 First Connection: Three Ways After flashing, the board reboots and starts Meshtastic.\nConnection Options Interface How to Connect When to Use Bluetooth Meshtastic app (Android/iOS) → scan devices Portable node, one active connection Wi-Fi Node creates AP → connect to your network → IP shown on screen Stationary node, multiple devices simultaneously USB/COM Connect via terminal (PuTTY, screen) Home node, debugging, direct access ⚠️ Bluetooth: only one active connection.\nWi-Fi: multiple devices can connect simultaneously (convenient for stationary nodes).\nUSB: reliable for setup and debugging, no wireless connection required.\nSetup via App (recommended) Install Meshtastic (Android) or the iOS version Launch the app and grant location and Bluetooth permissions Go to the \u0026ldquo;Devices\u0026rdquo; tab (router icon) → select the connection type (Bluetooth, Wi-Fi, or Serial), depending on the node\u0026rsquo;s mode (default is Bluetooth) → tap 🔍 Scan or + Add Confirm pairing Setup via Wi-Fi The node\u0026rsquo;s screen will display an IP address (usually 192.168.1.x) Connect to the node\u0026rsquo;s Wi-Fi network (password shown on screen) Open a browser and go to http://\u0026lt;node_IP_address\u0026gt; The web interface allows viewing data (e.g. JSON messages), but node configuration is not done here. Use one of the following for full setup: Meshtastic mobile app MeshApp Python CLI (meshtastic) over USB, BLE, or Wi-Fi 💡 IP Address: node gets address from your router (not 192.168.4.1!). Exact address displayed on OLED screen.\n👤 User Configuration Core Parameters Parameter Value Note Long Name [PE] ponfertato Full node name, visible to all (up to 20 chars, Cyrillic allowed) Short Name ponf Short identifier in messages (strictly 4 chars, Latin only) Role CLIENT or CLIENT_MUTE For cities with \u0026gt;200 nodes - CLIENT_MUTE (safe mode without rebroadcasting others\u0026rsquo; packets) Is Licensed (HAM) No If Yes → disable MQTT encryption (regulatory requirement) 💡 ShortName: exactly 4 characters! This appears in message headers. Examples: ponf, KST1, MOW2.\nAdditional Flags (Optional) Parameter Value Why Show on map Yes Allow display on public maps (controlled via MQTT) Ignore location requests No Respond to coordinate requests from other nodes Advanced User Settings Parameter Value Note Public Key (auto-generated) Don\u0026rsquo;t change manually; used for encryption Private Key (keep secret) Export and save securely on first setup Admin Key (empty) Fill only for remote node management Managed Mode No Don\u0026rsquo;t enable without configured Remote Admin 🌐 MQTT Setup for ONEmesh (RU) ONEmesh - map of Meshtastic devices in Russia. Connecting to their MQTT server lets your node appear on the map and exchange data with other participants.\n🔐 What\u0026rsquo;s transmitted via MQTT: text messages, device metrics (battery, signal), location (if enabled). Data goes to the map and regional Telegram chats per city settings.\nCore Parameters Parameter Value Note MQTT Address mqtt.onemesh.ru Community server (domain, not IP) Port 8883 (TLS) / 1883 (no TLS) Port auto-selected when TLS enabled Username onemesh Default; onemeshz / onemeshd for downlink Password onecat Shared for all project participants Encryption enabled Yes Encrypt MQTT traffic; requires PSK: AQ== in channel JSON enabled No Not needed for map, adds overhead TLS enabled Yes Encrypt connection; if errors → try No + port 1883 Root topic msh/RU/KST KST = Kostroma city code (code list) Proxy to client Yes (Bluetooth) / No (Wi-Fi) Not needed with direct Wi-Fi Map reports Yes Allow sending reports for map display I agree Yes Confirm geodata transmission rules Precision 729 m Coordinate precision on public map (~15 bits) Map report interval 3600 s (1 hour) Minimum report sending interval 💡 Tip: if \u0026ldquo;Save\u0026rdquo; button is inactive - fill settings in stages: basics first (address, login, password), then map, then extra options.\nUsername Modes Username Downlink When to Use onemesh ❌ Disabled Most users - safe mode, uplink only onemeshz ✅ Zero-hop If you need internet data but won\u0026rsquo;t rebroadcast over radio (zero-hop policy) onemeshd ✅ Full Only for integrations, connecting network segments; not recommended for regular nodes - adds airtime load ⚠️ Using onemeshd with Downlink enabled can overload local network with internet packets. Use consciously and only with full understanding.\nAdvanced MQTT Parameters Parameter Value Note Connection Retry Interval 30 sec How often to retry reconnect on drop Keepalive Interval 60 sec Connection liveness check interval QoS Level 0 Quality of Service: 0 = fire-and-forget (optimal for Meshtastic) Retain Messages No Don\u0026rsquo;t retain last messages on broker Topic Filter msh/RU/KST/# Subscribe to subtopics (for integrations) Common MQTT Issues Symptom Possible Cause Solution Connection refused Wrong login/password or port Check onemesh/onecat, port 8883 with TLS TLS handshake failed Certificate or time sync issue Check NTP sync, temporarily disable TLS for test No messages on map Wrong Root topic or PSK Verify: msh/RU/KST, channel with PSK: AQ== MQTT disconnected Unstable internet on node/phone Check connection, increase Map report interval Message not appearing Downlink disabled on server for onemesh Use onemeshz if downlink needed 📡 LoRa and Channel Settings LoRa Section Parameter Value Why Region Russia Auto-sets 433 MHz, power ≤20 dBm, and MQTT root topic Modem Preset LongFast Range/speed balance for urban conditions Frequency Slot 2 Public interval for RU868 (avoid conflicts) Transmit Power 20 dBm Max allowed for amateur use in RF Boosted RX Gain On Improves weak signal reception (critical for urban) Hop Limit 5 Max hops; enough for city, doesn\u0026rsquo;t overload airtime Ignore MQTT No Accept packets that came via internet (from MQTT neighbors) OK to MQTT Yes ⚠️ Critical: allows neighbors to relay your data to OneMesh map Advanced LoRa Parameters Parameter Value Note Bandwidth 250 kHz Channel bandwidth; don\u0026rsquo;t change when using presets Spreading Factor 11 Spreading factor; higher = farther but slower Coding Rate 5 (4/5) Error correction; balance reliability/speed Frequency Offset 0.0 Hz Crystal frequency correction; change only for calibration Override Duty Cycle No Don\u0026rsquo;t override airtime restrictions SX126x RX Boosted Gain On Hardware RX gain boost on SX1262 Channels - Detailed Configure the Primary channel (index 0):\nParameter Value Note Role Primary Only one channel can be primary; device telemetry goes through it Name LongFast Exactly this: public network filters packets by this name PSK AQ== Base encryption key for OneMesh (128-bit); required if MQTT encryption enabled Uplink enabled Yes Send data from this channel to MQTT server Downlink enabled No Don\u0026rsquo;t receive from MQTT (unless using onemeshz/onemeshd) Position enabled Yes Transmit coordinates via this channel Precise location No Hide exact coordinates from other nodes in channel Precision 182 m Position precision transmitted in channel (~17 bits) Muted No Don\u0026rsquo;t mute channel (otherwise messages won\u0026rsquo;t be visible) Secondary Channel (Optional, Index 1) Parameter Value Note Role Secondary Additional channel for private groups or bots Name [PE] Backup Any name \u0026lt;12 bytes (Latin) PSK (generate your own) Private key for your group Uplink / Downlink No Don\u0026rsquo;t send to public MQTT Position No Don\u0026rsquo;t transmit coordinates in private channel Precision 45 m Maximum precision for private use ✅ Important: at least one channel must have PSK: AQ== or be unencrypted for OneMesh server to accept packets.\n💡 Secondary channels are created via + in the app. They don\u0026rsquo;t interfere with main traffic and are useful for private communication.\nChannel Management: Tips Channel order: Primary must be first (index 0) - system telemetry goes through it. Channel names: use Latin, no spaces or special characters. PSK lengths: supported: 0 (no encryption), 8, 128, 256 bits. OneMesh requires AQ== (8-bit). Export/import: channel settings can be exported to JSON for quick deployment on other nodes. 📍 Position Settings Fixed Coordinates (for Stationary Nodes) Parameter Value Recommendation Fixed position On For nodes without GPS module Latitude 57.742 Kostroma latitude, no trailing zeros (enter as 57.742, not 57.74200) Longitude 40.978 Kostroma longitude, same as above Altitude 100 Altitude above sea level (approx., in meters) 💡 Coordinates stored as integer × 1e7. In app, enter with 6 decimal places.\nPosition Packet - Intervals and Precision Parameter Value Why Position broadcast interval 7200 s (2 hours) Balance between map freshness and airtime load Smart position No Fixed interval more reliable for stationary node Smart position min distance 100 m Min distance to trigger smart broadcast Smart position min interval 300 s Min interval between smart broadcasts Position flags ALTITUDE + TIMESTAMP Transmit only altitude and timestamp (less traffic) Provide location to network Yes Allow coordinate transmission to network (controlled via OK to MQTT) Advanced Position Settings Parameter Value Note GPS Enabled No Disable if no module; saves power GPS Update Interval 60 sec How often to poll GPS (if enabled) GPS Attempt Time 0 Don\u0026rsquo;t limit satellite search time RX/TX/Enable GPIO 0 Pins for external GPS module (defaults) Broadcast Smart Minimum Distance 100 m Min movement to trigger smart broadcast Broadcast Smart Minimum Interval 300 sec Min time between smart broadcasts 🔐 For privacy: reduce Precision in channel (182 m) and Map precision (729 m), or set fixed coordinates away from real location.\n⚙️ Additional Modules Neighbor Info Parameter Value Note Enabled Yes For \u0026ldquo;Neighbors\u0026rdquo; layer on OneMesh map Update interval 14400 s (4 hours) Minimum interval, don\u0026rsquo;t reduce - extra airtime load Transmit over LoRa No Don\u0026rsquo;t transmit neighbor data over radio (only via MQTT) 🗺️ Map will show layers \u0026ldquo;Who heard this device\u0026rdquo; and \u0026ldquo;Who this device heard\u0026rdquo; - useful for coverage analysis.\nDevice - Role and Rebroadcast Parameter Value When to Use Role CLIENT_MUTE In cities with \u0026gt;200 nodes - safe mode without rebroadcasting others\u0026rsquo; packets CLIENT If network is small or you have good antenna/location - can help network Rebroadcast mode CORE_PORTNUMS_ONLY Rebroadcast only basic packet types (position, text) - optimal for city ALL Rebroadcast everything - only for tests or very small networks Node info broadcast interval 43200 s (12 hours) How often to broadcast info about yourself; 12h is enough for monitoring Double tap as button No Prevent accidental triggers Disable triple click Yes Prevent false beacons LED heartbeat disabled No Visual operation indicator (LED blinking) Advanced Device Settings Parameter Value Note Button GPIO 0 Button pin (default) Buzzer GPIO 0 Buzzer pin (default) Buzzer Mode ALL_ENABLED Buzzer mode: DISABLED, ALERTS_ONLY, ALL_ENABLED TZDEF GMT-3 Timezone for local time Is Managed No Managed mode (only for admin nodes) Serial Enabled No Serial console (for debugging) Debug Log API No Output debug logs (not for production) Timezone Parameter Value Note Timezone GMT+3 (Moscow) For correct time display in logs and timestamps Use phone timezone Button Press to populate the timezone from the phone\u0026rsquo;s system settings Power - for Stability Parameter Value Note Power Saving Mode No Stationary node with USB power On Battery Shutdown After 0 sec Don\u0026rsquo;t shut down on power loss (if UPS present) ADC Multiplier Override 1.0 Battery voltage calibration Wait Bluetooth Secs 0 With direct WiFi, don\u0026rsquo;t wait for BLE Min Wake Secs 30 Min active time after receiving packet INA219 Address 0 Power monitor address (auto-detect) Display - OLED Optimization Parameter Value Note Screen Timeout 60 sec OLED timeout for power saving GPS Format UNUSED Coordinate format on screen (not used with fixed position) Auto Screen Carousel 0 Disable auto window rotation Compass North Top Yes Fix north to top of compass Flip Screen No Don\u0026rsquo;t flip screen (per body orientation) Units METRIC Metric system (°C, m, km/h) OLED Type OLED_AUTO Auto-detect display controller Display Mode DEFAULT Standard display mode Heading Bold Yes Bold heading for better readability Wake on Tap or Motion No Disable wake on motion (no accelerometer on V4) Bluetooth - When WiFi Off Parameter Value Note Enabled No With WiFi enabled, Bluetooth auto-disables on ESP32 Pairing Mode FIXED_PIN If enabling - use fixed PIN Fixed PIN 123456 → change! Must change to random 6-digit code Network - WiFi for Stationary Node Parameter Value Note WiFi Enabled Yes Direct connection to router SSID / PSK \u0026lt;your_data\u0026gt; 2.4 GHz networks only Enable Local UDP Broadcast No Not required for OneMesh NTP Server pool.ntp.org More reliable than default meshtastic.pool.ntp.org Address Mode DHCP Auto IP assignment IPv6 Enabled No Not used in current config ⚠️ With WiFi enabled, Bluetooth auto-disables on ESP32 architecture.\n🧩 Module Settings (Continued) Telemetry Parameter Value Note Send Device Telemetry Yes Enable for node status monitoring Device Metrics Interval 900 sec (15 min) How often to send device metrics Power Metrics Enabled Yes Critical for power monitoring Power Metrics Interval 300 sec (5 min) How often to send power data Environment Metrics Enabled No If no BME280/BME680 sensors Air Quality Enabled No Only for BME680 Display Metrics on Screen Yes Show metrics on OLED Display Fahrenheit No Metric system (°C) Canned Messages Parameter Value Note Enabled Yes Convenient for quick replies Messages Test link,On air,73!,Coordinates received Comma-separated, no spaces after Send Bell No Don\u0026rsquo;t send bell character with messages Rotary Encoder No If no encoder connected Disabled Modules (Recommendation for OneMesh) Module State Why Serial No Console not used External Notification No Without external piezo/LED modules Store \u0026amp; Forward No Only for REPEATER/ROUTER Range Test No Creates excess traffic Audio No Not supported on Heltec V4 Remote Hardware No Not used Ambient Lighting No Save power Detection Sensor No Without external GPIO sensors Paxcounter No Excess traffic for OneMesh Status Message No Not needed for stationary node 🔑 Critical Flags and Application Order Channel Name: Primary must be exactly LongFast. PSK: AQ== in primary channel is required for OneMesh filtering. OK to MQTT: On - without this, neighbors can\u0026rsquo;t relay your packets to server. Save Order (UI bug workaround): LoRa → Region → save Channels → name + PSK + Uplink/Downlink → save MQTT → basic params → save MQTT → Map Reports → save separately Position / Device / Power → save Reboot node Verification: In app: MQTT → status Connected On map: node appears within 1–3 hours In LongFast chat: messages from neighbors visible 🔧 Optimal Flashing Process For Heltec V4 (Bootloader Workaround) Due to a Heltec V4 bootloader quirk, the standard order doesn\u0026rsquo;t always work. Optimal process:\nDisconnect battery and USB from the board Open web flasher Select device: Heltec V4, firmware: 2.7.21 Click Erase Flash and Install Hold the PRG button on the board While holding PRG, plug in the USB cable Observe: brief red flash → USB JTAG appears in port dropdown Release PRG, select USB JTAG, click Connect Wait for flashing to complete After Leaving... message, press the RST button (reset) 💡 Note: this process is described in meshtastic/firmware#8543\n📤 First Messages Between Two Nodes Preparation Flash both boards per instructions above On each, configure: Same region (Russia) Same channel with identical PSK (AQ==) Position enabled: Yes (for testing) Place nodes 10–50 m apart (for initial test) Test On first node in app: Messages → + → type text → Send On second node: incoming message should appear Check Map tab - if MQTT is enabled, both nodes should appear on map within an hour Troubleshooting Symptom Check Fix No messages Verify channels have same PSK Copy key exactly, no spaces Node not on map Check MQTT enabled, Map reports, internet on phone/node Reboot node (RST), wait 1–2 report cycles MQTT connection error Verify TLS enabled, root topic Try disabling TLS; ensure Root topic = msh/RU/XXX No radio connection Check antenna, region, Hop limit Attach antenna, set Region: Russia, Hop limit: 5 🆘 Help and Community 🗺️ ONEmesh Map - network visualization 💬 Telegram Group - questions, help, city coordination 📘 Official Meshtastic Docs 🐙 Firmware Repository 🔧 Heltec V4 Specs ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/mesh/practice/","summary":"\u003cblockquote\u003e\n\u003cp\u003e📌 \u003cstrong\u003eThis is Part 2 of the series\u003c/strong\u003e. \u003ca href=\"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/mesh/intro/\"\u003ePart 1: Theory\u003c/a\u003e explains why this matters.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"-unboxing-and-preparation\"\u003e📦 Unboxing and Preparation\u003c/h2\u003e\n\u003ch3 id=\"heltec-v4-contents\"\u003eHeltec V4 Contents\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eComponent\u003c/th\u003e\n          \u003cth\u003ePurpose\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eBoard ~60×30 mm\u003c/td\u003e\n          \u003ctd\u003eESP32-S3R2 + SX1262, OLED 128×64, USB-C\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAntenna (IPEX)\u003c/td\u003e\n          \u003ctd\u003eConnect to \u003ccode\u003eANT\u003c/code\u003e port - \u003cstrong\u003emandatory!\u003c/strong\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eUSB-C cable\u003c/td\u003e\n          \u003ctd\u003ePower + flashing + debugging\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePins (optional)\u003c/td\u003e\n          \u003ctd\u003eFor external sensors/antennas\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cblockquote\u003e\n\u003cp\u003e⚠️ \u003cstrong\u003eImportant\u003c/strong\u003e: without antenna connected, the radio module may be damaged. Always attach antenna before powering on.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3 id=\"heltec-v4-specifications\"\u003eHeltec V4 Specifications\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eComponent\u003c/th\u003e\n          \u003cth\u003eDescription\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eMCU\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eESP32-S3R2 (WiFi + Bluetooth)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eLoRa Transceiver\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eSemtech SX1262\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eFrequencies\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e863–870 MHz (EU), 902–928 MHz (US)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eDisplay\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003e0.96\u0026quot; OLED 128×64\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePower\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eUp to +28±1 dBm (High Power option)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePower Supply\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eUSB-C + optimized LiPo management\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eConnectors\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003eUSB-C, U.FL/IPEX for LoRa, 1.25-8Pin GNSS, 1.25-2Pin Solar\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eForm Factor\u003c/strong\u003e\u003c/td\u003e\n          \u003ctd\u003ePin-compatible with V3/V3.1\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003chr\u003e\n\u003ch2 id=\"-flashing-web-flasher\"\u003e⚡ Flashing: Web Flasher\u003c/h2\u003e\n\u003cp\u003eOfficial flasher: \u003ca href=\"https://flasher.meshtastic.org\"\u003ehttps://flasher.meshtastic.org\u003c/a\u003e\u003c/p\u003e","title":"Heltec V4: Practice. Flashing, Setup, First Messages. Part 2"},{"content":"PostgreSQL doesn\u0026rsquo;t support in-place upgrades between major versions (15 → 17, 17 → 18). Data must be migrated logically: via dump and restore.\nWhy it\u0026rsquo;s important:\n✅ New versions = security fixes, optimizations, new features ✅ Support for modern clients (Nextcloud, Mastodon, Authelia require recent versions) ✅ Predictability: same process for any project Docker complexity:\n❌ Can\u0026rsquo;t just change image tag - data format is incompatible ❌ pg_upgrade requires simultaneous access to old/new binaries - breaks container isolation ✅ Solution: pg_dumpall → new container → psql \u0026lt; dump 📋 Prerequisites Before starting, ensure:\nTerminal access with docker and docker compose permissions ~2× database size free on disk (for dump + archive) Know DB container name (nextcloud-postgres) and user (nextcloud) Have docker-compose.yml with postgres service definition Application (Nextcloud/Mastodon) is stopped or in maintenance mode 💡 When in doubt - make a full volume backup first: tar czf backup-volume.tar.gz /var/lib/docker/volumes/...\nStep 1: Logical Backup # Create dump of all databases, roles, and global settings docker exec nextcloud-postgres pg_dumpall -U nextcloud \u0026gt; pg_dumpall_$(date +%F).sql # Verify size and integrity ls -lh pg_dumpall_*.sql tail -10 pg_dumpall_*.sql # should end with \u0026#34;;\u0026#34; ⚠️ If the user lacks superuser rights, use -U postgres.\nStep 2: Physical Volume Archive (Insurance) # Stop DB docker compose stop postgres # Find volume name docker volume ls | grep nextcloud_database # Archive raw data sudo tar czf postgres-volume-$(date +%F).tar.gz \\ -C /var/lib/docker/volumes/nextcloud_database/_data . Step 3: Remove Old Container and Volume docker compose down postgres docker volume rm nextcloud_database Step 4: Update docker-compose.yml Choose one option based on your target version.\n✅ Option A: PostgreSQL 15 / 16 / 17 (no path changes) services: postgres: image: postgres:17-alpine # or 15, 16 volumes: - database:/var/lib/postgresql/data ✅ Option B: PostgreSQL 18+ (new standard) services: postgres: image: postgres:18-alpine volumes: - database:/var/lib/postgresql # ← mount parent directory # Container will auto-create /var/lib/postgresql/18/docker inside 🔧 Option C: PostgreSQL 18+ with backward compatibility services: postgres: image: postgres:18-alpine volumes: - database:/var/lib/postgresql/data environment: PGDATA: /var/lib/postgresql/data # ← force old path 💡 Recommendation: use Option B. It aligns with Debian/Alpine standards and simplifies future pg_upgrade --link.\nStep 5: Start New DB docker compose up -d postgres sleep 20 # wait for initdb docker exec nextcloud-postgres pg_isready -U nextcloud -d nextcloud # Expected: \u0026#34;accepting connections\u0026#34; Step 6: Restore Data docker exec -i nextcloud-postgres psql -U nextcloud \u0026lt; pg_dumpall_*.sql 🟡 Normal errors in logs:\nERROR: role \u0026#34;nextcloud\u0026#34; already exists ERROR: database \u0026#34;nextcloud\u0026#34; already exists The new container already created the role/DB from stack.env. psql ignores duplicates and correctly imports tables. Just continue.\nStep 7: Final Verification # Version docker exec nextcloud-postgres psql -U nextcloud -c \u0026#34;SELECT version();\u0026#34; # Data path docker exec nextcloud-postgres psql -U nextcloud -c \u0026#34;SHOW data_directory;\u0026#34; # ≤17: /var/lib/postgresql/data # ≥18: /var/lib/postgresql/18/docker # Tables docker exec nextcloud-postgres psql -U nextcloud -d nextcloud -c \u0026#34;\\dt\u0026#34; 🔄 Rollback (If Something Goes Wrong) docker compose down # Revert old image and path (example for v17) sed -i \u0026#39;s/postgres:18/postgres:17/\u0026#39; docker-compose.yml sed -i \u0026#39;s|/var/lib/postgresql$|/var/lib/postgresql/data|\u0026#39; docker-compose.yml # Restore volume sudo rm -rf /var/lib/docker/volumes/nextcloud_database/_data/* sudo tar xzf postgres-volume-*.tar.gz -C /var/lib/docker/volumes/nextcloud_database/_data/ docker compose up -d postgres ⚠️ FAQ # \u0026#34;What happens if I run 18 with volumes:/var/lib/postgresql/data?\u0026#34; → Container won\u0026#39;t find data at the new path, runs initdb, and creates an empty DB. Old files remain untouched in the volume. # \u0026#34;How to check the path after startup?\u0026#34; → SHOW data_directory; inside psql. # \u0026#34;Can I use pg_upgrade instead of dump?\u0026#34; → In Docker, it requires simultaneous mounting of old/new binaries, breaking container isolation. Dump/restore is more reliable for containerized environments. # \u0026#34;Will 18→19 work the same way?\u0026#34; → Yes. Each major upgrade changes the subdirectory (18/docker → 19/docker). One `/var/lib/postgresql` volume will hold all versions in parallel. Links 🐘 PGDATA Change Discussion 🐳 Official PostgreSQL Docker Image 🗄️ pg_dumpall Reference 🔄 Nextcloud PostgreSQL Guide ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/docker/postgres-upgrade/","summary":"\u003cp\u003ePostgreSQL doesn\u0026rsquo;t support in-place upgrades between major versions (15 → 17, 17 → 18). Data must be migrated logically: via dump and restore.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhy it\u0026rsquo;s important\u003c/strong\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e✅ New versions = security fixes, optimizations, new features\u003c/li\u003e\n\u003cli\u003e✅ Support for modern clients (Nextcloud, Mastodon, Authelia require recent versions)\u003c/li\u003e\n\u003cli\u003e✅ Predictability: same process for any project\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eDocker complexity\u003c/strong\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e❌ Can\u0026rsquo;t just change image tag - data format is incompatible\u003c/li\u003e\n\u003cli\u003e❌ \u003ccode\u003epg_upgrade\u003c/code\u003e requires simultaneous access to old/new binaries - breaks container isolation\u003c/li\u003e\n\u003cli\u003e✅ Solution: \u003ccode\u003epg_dumpall\u003c/code\u003e → new container → \u003ccode\u003epsql \u0026lt; dump\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"-prerequisites\"\u003e📋 Prerequisites\u003c/h2\u003e\n\u003cp\u003eBefore starting, ensure:\u003c/p\u003e","title":"PostgreSQL in Docker: Major Version Migration Without Data Loss"},{"content":"When running apps via Flatpak (Discord, OBS, Firefox, etc.), you may see:\nWarning: While downloading http://ciscobinary.openh264.org/libopenh264-2.5.1-linux64.7.so.bz2: Server returned status 403 Or in logs:\nFailed to load OpenH264 library: openh264 cannot be opened Symptoms:\n❌ Video calls show black screen or don\u0026rsquo;t work ❌ OBS screen recording fails with encoding error ❌ Webcam doesn\u0026rsquo;t transmit video in browser Cause: Cisco\u0026rsquo;s server (ciscobinary.openh264.org) blocks automated downloads of libopenh264 due to licensing/policy reasons. Status 403 = \u0026ldquo;forbidden\u0026rdquo;.\n✅ Solution: Replace OpenH264 with ffmpeg-full Instead of the problematic codec, install the full-featured ffmpeg-full from Flathub. It includes all necessary codecs including H.264 and doesn\u0026rsquo;t rely on external downloads.\nStep 1: Install ffmpeg-full flatpak install org.freedesktop.Platform.ffmpeg-full When prompted for version, select the latest (usually 24.08 or higher):\nWhich do you want to use (0 to abort)? [0-6]: 3 Step 2: Block OpenH264 download flatpak mask org.freedesktop.Platform.openh264 What this does:\ninstall - adds full-featured FFmpeg with H.264 support mask - prevents Flatpak from trying to download the problematic openh264 Step 3: Restart the application # For user apps flatpak kill org.discordapp.Discord # replace with your app-id flatpak run org.discordapp.Discord # Or just reboot 🔍 Verify the fix # Check that ffmpeg-full is installed flatpak list | grep ffmpeg-full # Ensure openh264 is masked flatpak mask --list | grep openh264 # Check app logs (optional) flatpak run --command=sh org.discordapp.Discord -c \u0026#34;journalctl --user -n 50\u0026#34; If warnings about 403 or openh264 are gone - the fix worked.\n⚙️ Advanced: User-space installation (no sudo) If you use Flatpak in user mode (--user), commands differ slightly:\n# Install in user-space flatpak install --user org.freedesktop.Platform.ffmpeg-full # Mask in user-space flatpak mask --user org.freedesktop.Platform.openh264 Verify:\nflatpak list --user | grep ffmpeg-full flatpak mask --user --list | grep openh264 🔄 If it didn\u0026rsquo;t help: additional steps 1. Update repository metadata flatpak update --appstream flatpak update 2. Rebuild runtime cache # Clear cache (safe, files will reinstall if needed) flatpak repair 3. Check which app uses the codec # Find app-id flatpak list | grep -i discord # Run with debug flatpak run --command=sh org.discordapp.Discord -c \u0026#34;env | grep -i h264\u0026#34; 4. Alternative: Use system FFmpeg If Flatpak version doesn\u0026rsquo;t work, you can allow the app to access system libraries:\n# Allow access to /usr/lib (use with caution) flatpak override --user --filesystem=/usr/lib org.discordapp.Discord ⚠️ This reduces container isolation - use only if you\u0026rsquo;re sure.\n📊 Solution Comparison Method Pros Cons For Whom ffmpeg-full + mask ✅ Works immediately, no sudo, updates via Flatpak ❌ Increases install size (~100 MB) Most users System FFmpeg ✅ Uses already-installed libraries ❌ Requires permission setup, reduces isolation Advanced users Manual openh264 download ✅ Minimal size ❌ Unstable, requires re-download on updates Not recommended ⚠️ FAQ # \u0026#34;Will this break other apps?\u0026#34; → No. Masking applies only to `openh264`, and `ffmpeg-full` is backward compatible. # \u0026#34;Why not fix Cisco\u0026#39;s server?\u0026#34; → It\u0026#39;s a licensing policy. We can\u0026#39;t change it, but we can work around it. # \u0026#34;What if I really want openh264?\u0026#34; → Try downloading the library manually to `~/.var/app/*/cache/openh264/`, but it\u0026#39;s unstable. # \u0026#34;Will ffmpeg-full update automatically?\u0026#34; → Yes, via `flatpak update`. Masking persists. Links 🐧 Flatpak Documentation 🎬 FFmpeg in Flathub 🚫 OpenH264 License Info 🛠 Flatpak Mask Command ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/linux/flatpak-openh264/","summary":"\u003cp\u003eWhen running apps via Flatpak (Discord, OBS, Firefox, etc.), you may see:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eWarning: While downloading\n  http://ciscobinary.openh264.org/libopenh264-2.5.1-linux64.7.so.bz2:\n  Server returned status 403\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eOr in logs:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eFailed to load OpenH264 library: openh264 cannot be opened\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003eSymptoms\u003c/strong\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e❌ Video calls show black screen or don\u0026rsquo;t work\u003c/li\u003e\n\u003cli\u003e❌ OBS screen recording fails with encoding error\u003c/li\u003e\n\u003cli\u003e❌ Webcam doesn\u0026rsquo;t transmit video in browser\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eCause\u003c/strong\u003e: Cisco\u0026rsquo;s server (\u003ccode\u003eciscobinary.openh264.org\u003c/code\u003e) blocks automated downloads of \u003ccode\u003elibopenh264\u003c/code\u003e due to licensing/policy reasons. Status \u003ccode\u003e403\u003c/code\u003e = \u0026ldquo;forbidden\u0026rdquo;.\u003c/p\u003e","title":"Flatpak: HTTP 403 Error Loading OpenH264 - Quick Fix"},{"content":"🎮 Why this matters Running games via Steam on Linux often feels like \u0026ldquo;dancing with a tambourine\u0026rdquo;: different engines need different flags, AMD and NVIDIA require different environment variables, and tools like Gamescope and MangoHud must be manually inserted into launch commands.\nSolution: steamscope.sh - a wrapper script that:\n✅ Auto-detects GPU (AMD/NVIDIA) and applies appropriate optimizations ✅ Supports engine-specific flags: Source, Unreal, Unity ✅ Integrates Gamescope, Gamemode, MangoHud, FSR in one command ✅ Works as %command% in Steam launch options ✅ Doesn\u0026rsquo;t break standard launch - everything is optional 💡 The script doesn\u0026rsquo;t replace Proton or Steam - it makes their work predictable and configurable.\n📦 Installation Step 1: Download the script # Create directory (if missing) mkdir -p ~/.steam/steam/ # Download script curl -o ~/.steam/steam/steamscope.sh \\ https://gist.githubusercontent.com/ponfertato/85fc964664423eae1ac0a7ee91d53db6/raw/steamscope.sh # Make executable chmod +x ~/.steam/steam/steamscope.sh Step 2: Configure game in Steam Right-click game → Properties In Launch Options, add: ~/.steam/steam/steamscope.sh %command% (Optional) Add flags: ~/.steam/steam/steamscope.sh --gamemode --mangohud --engine=source %command% Done. When launching the game, the script will automatically apply settings.\n⚙️ Launch parameters (by category) 🚀 Performance Flag Description For whom --gamemode Enables gamemoderun for process priority Everyone, especially on weak systems --fsr Enables FSR upscaling via VKD3D (AMD) / DXVK (NVIDIA) AMD GPU, low native FPS --dxvk Forces DXVK instead of D9VK Games with DirectX 9/10/11 👁 Monitoring Flag Description Example output --mangohud Shows overlay with FPS, CPU/GPU load, temps FPS: 87 │ CPU: 45% │ GPU: 72°C 🖥 Runtime mode Flag Description Why --gamescope Runs game in isolated Wayland session via Gamescope Stable FPS, adaptive sync, scaling --resolution=1280x720 Sets resolution for Gamescope (default: native) Testing, reducing load 🎯 Engines Flag Supported engines Example games --engine=source Source 1/2 CS2, TF2, Garry\u0026rsquo;s Mod, Left 4 Dead 2 --engine=unreal Unreal Engine 3/4/5 Risk of Rain 2, Deep Rock Galactic, Satisfactory --engine=unity Unity 7 Days to Die, Valheim, Among Us What each engine adds:\nSource: -high -threads N +mat_vsync 0 +fps_max 0 +exec autoexec.cfg Unreal: -dx12 -nomansky -notexturestreaming -nomovie Unity: -screen-width W -screen-height H -nolog -batchmode 🔧 How it works (under the hood) Auto-detect hardware # Script checks GPU via lspci GPU_INFO=$(lspci -k 2\u0026gt;/dev/null | awk \u0026#39;/VGA|3D/,/Kernel driver/ {if (/Kernel driver in use/) print $NF}\u0026#39; | tail -1) # For AMD: [[ \u0026#34;$GPU_INFO\u0026#34; == *\u0026#34;amdgpu\u0026#34;* ]] \u0026amp;\u0026amp; USE_AMD=true # → Adds: RADV_PERFTEST=aco, AMD_DEBUG=nodcc # For NVIDIA: [[ \u0026#34;$GPU_INFO\u0026#34; == *\u0026#34;nvidia\u0026#34;* ]] \u0026amp;\u0026amp; USE_NVIDIA=true # → Adds: PROTON_ENABLE_NVAPI=1, __NV_PRIME_RENDER_OFFLOAD=1 Building the final command The script builds the command in \u0026ldquo;layers\u0026rdquo;:\n[gamemoderun] → [mangohud] → [gamescope -- ...] → [GAME + engine flags] Each layer is added only if the corresponding flag is passed.\nHandling %command% Steam passes the launch command as %command%. The script:\nFinds the position after the executable (but not inside proton, steam-runtime, etc.) Inserts engine flags after the executable but before game arguments This ensures flags reach the game, not the launcher 🎯 Examples for popular games Counter-Strike 2 (Source Engine, AMD) ~/.steam/steam/steamscope.sh \\ --engine=source \\ --gamemode \\ --mangohud \\ --fsr \\ --gamescope \\ %command% What the game gets:\nProcess priority via gamemoderun MangoHud overlay with metrics FSR upscaling via VKD3D (for higher FPS) Launch in Gamescope with adaptive sync Optimized Source flags: -high -threads 8 +fps_max 0 Deep Rock Galactic (Unreal Engine, NVIDIA) ~/.steam/steam/steamscope.sh \\ --engine=unreal \\ --gamemode \\ --dxvk \\ --mangohud \\ %command% Highlights:\n--dxvk enables DXVK for better Vulkan compatibility on NVIDIA Unreal flags disable heavy effects: -nomansky -notexturestreaming UE5_ALLOW_LINUX_DEBUGGING=1 for Linux stability 7 Days to Die (Unity, cross-platform) ~/.steam/steam/steamscope.sh \\ --engine=unity \\ --gamemode \\ --fsr \\ --resolution=1280x720 \\ %command% Why:\n--resolution reduces load for smoother gameplay --fsr compensates detail loss with upscaling Unity flags disable logging: -nolog -batchmode 🛠 Configuration tips Start minimal # Game only (basic launch) ~/.steam/steam/steamscope.sh %command% # + monitoring ~/.steam/steam/steamscope.sh --mangohud %command% # + optimization ~/.steam/steam/steamscope.sh --gamemode --mangohud %command% Add parameters one by one - easier to find what breaks.\nIf the game crashes Disable --gamescope - most common source of conflicts Disable --gamemode - may conflict with system settings Check logs: journalctl -f | grep -i steam Resolution and scaling By default, script gets native resolution via xrandr To force change: --resolution=1280x720 Combined with --gamescope and --fsr gives flexible quality/performance control Localization The script sets:\nexport LANG=\u0026#34;ru_RU.UTF-8\u0026#34; export LC_ALL=\u0026#34;ru_RU.UTF-8\u0026#34; If game requires English locale - override in launch options:\nLANG=en_US.UTF-8 ~/.steam/steam/steamscope.sh %command% ⚠️ Common issues # \u0026#34;gamescope: command not found\u0026#34; → Install: # Arch: sudo pacman -S gamescope # Debian/Ubuntu: sudo apt install gamescope # Fedora: sudo dnf install gamescope # \u0026#34;gamemoderun: command not found\u0026#34; → Install: # All distros: sudo apt install gamemode or equivalent # Game ignores engine flags → Ensure %command% is at the end of the launch string → Verify the game actually uses the expected engine (not all \u0026#34;names\u0026#34; match reality) # No MangoHud overlay → Ensure mangohud is installed and in PATH → Some games require: export MANGOHUD_DLSYM=1 (script does this automatically) # Low FPS after enabling --fsr → FSR is upscaling, not magic: it boosts FPS at the cost of quality → Try lowering --resolution together with --fsr # Script doesn\u0026#39;t detect GPU → Ensure pciutils is installed: sudo apt install pciutils → Check output: lspci -k | grep -A2 -i vga 🔐 Security and privacy The script does not collect data, send anything over the network, or work outside the local system.\nWhat it does:\nReads lspci to detect GPU (for optimizations only) Sets environment variables for the game process Does not modify game or system files Recommendations:\nDownload script only from official gist Verify hash when updating (optional) Don\u0026rsquo;t pass sensitive data in script arguments 🗂 Pre-use checklist Installed dependencies: gamemode, mangohud, gamescope (optional) Downloaded script to ~/.steam/steam/steamscope.sh and made executable Tested launch of one game with minimal flags Verified %command% is at the end of launch options string Reviewed local regulations on overlay usage in games (if relevant) Links 🎮 Official script Gist 🐧 ProtonDB - game compatibility 🖥 Gamescope on GitHub ⚡ Gamemode on GitHub 👁 MangoHud on GitHub 🎯 FSR in VKD3D-Proton ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/linux/steamscope/","summary":"\u003ch2 id=\"-why-this-matters\"\u003e🎮 Why this matters\u003c/h2\u003e\n\u003cp\u003eRunning games via Steam on Linux often feels like \u0026ldquo;dancing with a tambourine\u0026rdquo;: different engines need different flags, AMD and NVIDIA require different environment variables, and tools like Gamescope and MangoHud must be manually inserted into launch commands.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSolution\u003c/strong\u003e: \u003ccode\u003esteamscope.sh\u003c/code\u003e - a wrapper script that:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e✅ Auto-detects GPU (AMD/NVIDIA) and applies appropriate optimizations\u003c/li\u003e\n\u003cli\u003e✅ Supports engine-specific flags: Source, Unreal, Unity\u003c/li\u003e\n\u003cli\u003e✅ Integrates Gamescope, Gamemode, MangoHud, FSR in one command\u003c/li\u003e\n\u003cli\u003e✅ Works as \u003ccode\u003e%command%\u003c/code\u003e in Steam launch options\u003c/li\u003e\n\u003cli\u003e✅ Doesn\u0026rsquo;t break standard launch - everything is optional\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 The script doesn\u0026rsquo;t replace Proton or Steam - it makes their work predictable and configurable.\u003c/p\u003e","title":"steamscope.sh: Universal Steam Launcher for Linux"},{"content":"Imagine: you\u0026rsquo;re hiking, at a dacha, in an area with poor signal - or you just want to communicate without carriers, clouds, and surveillance.\nSolution: decentralized LoRa network - low-power radio with range up to several kilometers.\n💡 This isn\u0026rsquo;t an internet replacement. It\u0026rsquo;s \u0026ldquo;internet for emergencies, privacy, and experiments\u0026rdquo;.\nWho this series is for:\n✅ Friends and relatives who want to understand \u0026ldquo;why do I need this\u0026rdquo; ✅ Beginners in radio/electronics (no soldering required!) ✅ Anyone who values privacy and infrastructure independence 📡 LoRa and mesh networks (in simple terms) LoRa (Long Range) Parameter Value Range 1–10 km urban, 50+ km line-of-sight Power ~100 mA transmit, ~10 mA idle Speed 0.3–50 kbps (text, coordinates, small data only) Frequency 433 MHz (RU), 868 MHz (EU), 915 MHz (US) Simple analogy:\n🥔 LoRa is like passing notes through a chain of friends. Slow, but far and without internet.\nMesh network Devices (nodes) relay messages to each other like a baton:\n[You] → [Node A] → [Node B] → [Friend] ↑ ↑ [Node C] → [Node D] Advantages:\n✅ No tower needed - network is built from users\u0026rsquo; devices ✅ Fault tolerance: if one node drops, message finds another path ✅ Scalability: more participants = better coverage 🔧 Why Heltec V4 specifically? HELTEC® LoRa 32 V4 - board based on ESP32-S3R2 + SX1262.\nSpecs Component Description ESP32-S3 240 MHz, WiFi + Bluetooth, 8 MB Flash, 8 MB PSRAM SX1262 LoRa transceiver (433/863-870/902-928 MHz), up to +28±1dBm Display 0.96\u0026quot; OLED 128×64 (for messages, status) Power 3.7V LiPo (via JST), USB-C for charging/flashing Form factor Compact (~60×30 mm), ready for pocket/backpack Why it\u0026rsquo;s great All-in-one: no soldering, no module assembly - board is ready to use Two radios: LoRa for long-range + WiFi/BT for setup Display: see messages, signal strength, battery - no phone needed Community: Meshtastic, PlatformIO, Arduino support - many ready solutions Price: ~$25–30 for a full node 💡 To start, you only need two boards: one for you, one for a friend. Already can exchange messages without internet.\n🗣️ Meshtastic: simple, works, for everyone Meshtastic - open-source project that turns boards like Heltec V4 into decentralized network nodes for text messages and coordinates.\nWhat it does ✅ Text chats (private and group) ✅ Coordinate sharing (GPS tracking with optional module) ✅ Multi-hop routing ✅ Encryption (optional, app-level) ✅ Cross-platform clients: Android, iOS, Web, Desktop Why start with it Criterion Why it\u0026rsquo;s beginner-friendly Setup Flash via browser, no code compilation UI Mobile app like a messenger Docs Detailed guides, active community Security Russian security guide Legality RU regulations compliance with proper settings Limitations (honestly) Limitation How to live with it Text and coordinates only Not for video/audio, but perfect for \u0026ldquo;I\u0026rsquo;m OK\u0026rdquo; Low speed Messages take seconds - normal for the range Depends on node count More participants = better network - invite friends! 🔐 Reticulum: for those who want more Reticulum - more advanced platform for decentralized networks.\nHow it differs from Meshtastic Meshtastic Reticulum Simplicity, chat focus Flexibility, protocol focus Ready-made app Library for building your own apps Text/coordinates only Text, files, VoIP, TCP/IP integration \u0026ldquo;For everyone\u0026rdquo; community \u0026ldquo;For devs and enthusiasts\u0026rdquo; community Why mention it now Future path: if you want more than chat - file transfer, local services Integration: Reticulum works over multiple transports (LoRa, WiFi, internet) - unified network from heterogeneous nodes Privacy: end-to-end encryption, anonymous IDs, resilient architecture 💡 Don\u0026rsquo;t worry: Meshtastic is enough to start. Reticulum is \u0026ldquo;next level\u0026rdquo; to revisit later.\n⚖️ Legality in Russia (important!) Radio frequency use is regulated. Here\u0026rsquo;s what to know:\nAllowed parameters for 868 MHz (RU) Parameter Value Frequency 868,7–869,2 MHz Power Up to 25 mW (≤14 dBm) without registration Modulation LoRa (allowed) Purpose Amateur use, experiments How to stay compliant Use ready firmware (Meshtastic) with regional settings (auto-sets power) Don\u0026rsquo;t amplify signal with external amps without permit Don\u0026rsquo;t transmit commercial traffic - personal/experimental data only Read the guide: Meshtastic regulations in RU ⚠️ This isn\u0026rsquo;t legal advice. When in doubt, consult a specialist.\n🔒 Security: what to do and what to avoid Security recommendations:\n✅ Do Enable channel encryption (pre-shared key) Use nicknames instead of real names Don\u0026rsquo;t send sensitive data (passwords, addresses) in plaintext Update firmware regularly ❌ Avoid Don\u0026rsquo;t use default encryption keys from examples Don\u0026rsquo;t share home/work coordinates in public channels Don\u0026rsquo;t rely on anonymity as 100% protection 💡 Encryption in Meshtastic protects from casual eavesdropping, not targeted state-level attacks.\n🎯 Use cases (for inspiration) For family / friends Scenario How it works Dacha communication Node at home + node in car = chat without cellular Hiking / fishing Group of 3–5 nodes = network for several km without internet Emergency backup When cellular is down - reserve channel for \u0026ldquo;I\u0026rsquo;m OK\u0026rdquo; For smart home Scenario Integration Garden sensors Node with humidity sensor → sends data to base node → Home Assistant Notifications HA event → message to local network → you see it on pocket node display Backup channel When internet drops - critical alerts go via LoRa For community Scenario Idea Neighborhood network 10–20 participants = district coverage, chat, coordinate sharing Event comms Festival, bike ride: temporary network without loading cellular towers Education Workshop for friends: \u0026ldquo;build your node in 15 minutes\u0026rdquo; Links 📡 Meshtastic Official 🔐 Meshtastic Security (RU) ⚖️ RU Regulations Guide 🌐 Reticulum Network 🛒 Heltec V4 on AliExpress (example, check availability) 📘 MeshWorks Introduction (RU) 📡 ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/mesh/intro/","summary":"\u003cp\u003eImagine: you\u0026rsquo;re hiking, at a dacha, in an area with poor signal - or you just want to communicate without carriers, clouds, and surveillance.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSolution\u003c/strong\u003e: decentralized LoRa network - low-power radio with range up to several kilometers.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 This isn\u0026rsquo;t an internet replacement. It\u0026rsquo;s \u0026ldquo;internet for emergencies, privacy, and experiments\u0026rdquo;.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003eWho this series is for\u003c/strong\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e✅ Friends and relatives who want to understand \u0026ldquo;why do I need this\u0026rdquo;\u003c/li\u003e\n\u003cli\u003e✅ Beginners in radio/electronics (no soldering required!)\u003c/li\u003e\n\u003cli\u003e✅ Anyone who values privacy and infrastructure independence\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"-lora-and-mesh-networks-in-simple-terms\"\u003e📡 LoRa and mesh networks (in simple terms)\u003c/h2\u003e\n\u003ch3 id=\"lora-long-range\"\u003eLoRa (Long Range)\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eParameter\u003c/th\u003e\n          \u003cth\u003eValue\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eRange\u003c/td\u003e\n          \u003ctd\u003e1–10 km urban, 50+ km line-of-sight\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePower\u003c/td\u003e\n          \u003ctd\u003e~100 mA transmit, ~10 mA idle\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSpeed\u003c/td\u003e\n          \u003ctd\u003e0.3–50 kbps (text, coordinates, small data only)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eFrequency\u003c/td\u003e\n          \u003ctd\u003e433 MHz (RU), 868 MHz (EU), 915 MHz (US)\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003eSimple analogy\u003c/strong\u003e:\u003c/p\u003e","title":"Heltec V4: Your Own Network Without Internet. Part 1: Why Bother?"},{"content":"The Problem After switching to HyperOS (POCO, Xiaomi), links from apps (Telegram, WhatsApp, etc.) open in the cloned Chrome account instead of the main one - even when the main Chrome is set as default browser.\nSymptoms:\nClick link → Chrome opens in second space Default browser settings show main Chrome Resetting settings doesn\u0026rsquo;t help Cause: HyperOS prioritizes cloned apps when handling intents, ignoring user preference.\n💡 Issue reproduces on MIUI 14 / HyperOS 1.0+ with \u0026ldquo;Dual Apps\u0026rdquo; / \u0026ldquo;Second Space\u0026rdquo; enabled.\n❌ Why simple fixes don\u0026rsquo;t work ADB removal (temporary) adb shell pm uninstall -k --user 999 com.android.chrome Problem: after reboot, Chrome in second space is quietly reinstalled. user 999 is the cloned profile ID, but HyperOS restores system apps on startup.\nDisable \u0026ldquo;Dual Apps\u0026rdquo; Downside: removes all cloned apps and their data. Not suitable if you need other duplicates (messengers, banking apps).\n✅ Solutions (by preference) Solution 1: Shizuku + AppManager (recommended) Remove Chrome from second space without root, keeping other cloned apps intact.\nStep 1: Install Shizuku Download Shizuku from F-Droid Launch app → \u0026ldquo;Start via wireless debugging\u0026rdquo; Enable wireless debugging in Developer Options: Settings → About phone → Tap \u0026ldquo;OS version\u0026rdquo; 7 times Settings → Additional settings → Developer options → ✅ Wireless debugging Follow Shizuku instructions to pair Step 2: Install AppManager Download AppManager from F-Droid Open app → grant access via Shizuku (automatic) Step 3: Remove Chrome from second space Find com.android.chrome (Google Chrome) Open app card → ⋮ → Uninstall for user Confirm removal Result: Chrome removed only from second space, main account unaffected.\nStep 4: Verify # Via ADB (optional) adb shell pm list packages --user 999 | grep chrome # Should be empty Solution 2: Change default browser If you don\u0026rsquo;t want to set up Shizuku:\nInstall alternative browser: Chrome Beta, Firefox, Brave Export bookmarks from main Chrome (sync with account) Clear main Chrome data (optional) Set new browser as default: Settings → Apps → Default apps → Browser Test link opening Pro: no root, Shizuku, or ADB required\nCon: need to adapt to new browser\nSolution 3: ADB script with auto-launch (advanced) If Shizuku doesn\u0026rsquo;t work, automate ADB commands:\n#!/bin/bash # remove-chrome-clone.sh adb wait-for-device adb shell pm uninstall -k --user 999 com.android.chrome echo \u0026#34;Chrome removed from second space\u0026#34; Auto-launch via Termux + ADB:\nInstall Termux Install ADB Keyboard or use adb tcpip Run script on boot via ~/.termux/boot/ Limitation: after phone reboot, script must be run manually (or set up auto-launch via Tasker).\n🔍 Diagnostics # Check if Chrome is installed in second space adb shell pm list packages --user 999 | grep chrome # Check default browser adb shell dumpsys package preferred | grep browser # View intent handlers for links adb shell dumpsys activity preferred-activities | grep -A5 \u0026#34;http\u0026#34; ⚠️ Common issues # Shizuku won\u0026#39;t start → Re-enable wireless debugging and re-pair → Restart Shizuku after system update # AppManager doesn\u0026#39;t see user 999 → Grant permissions via Shizuku: Settings → Apps → AppManager → Permissions → Restart AppManager # Chrome reinstalls after reboot → This is HyperOS behavior. Workaround: add script to auto-start (Termux + Tasker) → Or use Shizuku + AppManager with re-removal on boot (requires root) # Links still open in clone → Clear default settings: Settings → Apps → Manage apps → ⋮ → Reset defaults → Reboot phone Links 🔧 Shizuku on F-Droid 📱 AppManager on F-Droid 🤖 Termux on F-Droid 📘 Android Package Manager Docs ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/android/hyperos/chrome-dual-fix/","summary":"\u003ch2 id=\"the-problem\"\u003eThe Problem\u003c/h2\u003e\n\u003cp\u003eAfter switching to HyperOS (POCO, Xiaomi), links from apps (Telegram, WhatsApp, etc.) open in the cloned Chrome account instead of the main one - even when the main Chrome is set as default browser.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSymptoms\u003c/strong\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eClick link → Chrome opens in second space\u003c/li\u003e\n\u003cli\u003eDefault browser settings show main Chrome\u003c/li\u003e\n\u003cli\u003eResetting settings doesn\u0026rsquo;t help\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eCause\u003c/strong\u003e: HyperOS prioritizes cloned apps when handling intents, ignoring user preference.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Issue reproduces on MIUI 14 / HyperOS 1.0+ with \u0026ldquo;Dual Apps\u0026rdquo; / \u0026ldquo;Second Space\u0026rdquo; enabled.\u003c/p\u003e","title":"HyperOS: Remove Chrome from Second Space"},{"content":"Obtainium is an Android update manager that downloads apps directly from developer repositories (GitHub, GitLab, Codeberg, F-Droid), bypassing third-party stores.\nWhy you need it:\nGet updates faster than Google Play / F-Droid Avoid trackers and ads from third-party stores Control which versions are installed (stable, beta, pre-release) Automate updates without manual confirmation 💡 Obtainium doesn\u0026rsquo;t host apps - it only points where to download them. You always know the source.\n📦 Installation Download F-Droid (recommended) GitHub Releases First-run setup Open Obtainium → allow \u0026ldquo;Install unknown apps\u0026rdquo; (for Obtainium only) Settings → Installation method → select Shizuku (if configured) or System installer Settings → Update check interval → set frequency (recommended: 6–24 hours) Optional:\n✅ Show notifications for new versions ✅ Auto-download updates (requires stable internet) ✅ Auto-install (requires Shizuku) 🔍 Adding apps Method 1: By repository URL Source: GitHub URL: https://github.com/RikkaApps/Shizuku Filter: Releases → Stable only Format: APK (universal) or arm64-v8a (for performance) Steps:\nIn Obtainium: \u0026ldquo;+\u0026rdquo; → \u0026ldquo;Add app\u0026rdquo; Paste repository URL Tap \u0026ldquo;Check\u0026rdquo; - Obtainium shows available versions Configure filters (tags, pre-releases, architecture) Save Method 2: From catalog Obtainium has a built-in catalog of popular apps:\nMenu → \u0026ldquo;Catalog\u0026rdquo; → select app → \u0026ldquo;Add\u0026rdquo; Filters applied automatically Method 3: Import list // backup.json - exported config { \u0026#34;apps\u0026#34;: [ { \u0026#34;sourceId\u0026#34;: \u0026#34;github\u0026#34;, \u0026#34;url\u0026#34;: \u0026#34;https://github.com/user/repo\u0026#34;, \u0026#34;includePrereleases\u0026#34;: false, \u0026#34;filterReleaseTitlesByRegEx\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;filterReleaseNotesByRegEx\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;versionExtractionRegEx\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;apkFilterRegEx\u0026#34;: \u0026#34;arm64-v8a\u0026#34;, \u0026#34;invertAPKFilter\u0026#34;: false } ] } Import: Settings → \u0026ldquo;Backup\u0026rdquo; → \u0026ldquo;Restore\u0026rdquo;\n⚙️ Advanced settings Version filters Parameter Example Description Stable only ✅ Ignore beta, alpha, rc Regex (title) ^v[0-9.]+$ Accept only versions like v1.2.3 Regex (notes) (?i)android Search keywords in release notes APK filters Parameter Example Purpose Filter by name arm64-v8a Download only for 64-bit devices Invert filter ✅ Exclude specific architectures Min size 1000000 (1 MB) Filter out empty/corrupted files Notifications \u0026amp; auto-update Settings → Notifications: ✅ Show on new version ✅ Sound / Vibration (optional) Settings → Auto-update: ✅ Enable (requires Shizuku for silent install) ⏰ Interval: 6 hours 🌙 Only when charging + WiFi (recommended) 🔗 Shizuku integration Why Shizuku for Obtainium Without Shizuku With Shizuku Manual install confirmation Fully automatic installation Doesn\u0026rsquo;t work with split-APK Supports all formats Requires \u0026ldquo;Unknown sources\u0026rdquo; Installs via system Package Manager Setup Ensure Shizuku is running (status \u0026ldquo;Running\u0026rdquo;) In Obtainium: Settings → Installation method → Shizuku Grant access on first install attempt Test: update any app Check logs (if something fails):\nadb logcat | grep -i obtainium adb logcat | grep -i shizuku 📊 Comparison with alternatives Manager Sources Auto-install Split-APK Privacy Obtainium GitHub, GitLab, Codeberg, F-Droid, direct links ✅ (with Shizuku) ✅ 🔒 High F-Droid F-Droid repos only ❌ ❌ 🔒 High Aurora Store Google Play (anonymously) ❌ ✅ 🔐 Medium APKUpdater GitHub, F-Droid, APKMirror ❌ ⚠️ Partial 🔐 Medium Google Play Play Store only ✅ ✅ 🔓 Low When to choose Obtainium:\nYou trust developers directly You want updates faster than official stores You need split-APK support and flexible filters Privacy and source control matter to you ⚠️ Common issues # \u0026#34;Failed to fetch version info\u0026#34; → Check internet connection → Ensure repo is public (or add token in settings) → Try \u0026#34;Check manually\u0026#34; in app card # \u0026#34;Installation canceled by user\u0026#34; → Without Shizuku: expected - confirm install manually → With Shizuku: check if service is running and permissions granted # \u0026#34;Unsupported APK format\u0026#34; → Enable \u0026#34;Support split-APK\u0026#34; in settings → Update Obtainium to latest version → Use SAI as fallback installer # \u0026#34;App not updating despite newer version\u0026#34; → Check filters: new version may be marked as pre-release → Clear app cache: Settings → Apps → Obtainium → Storage → Clear cache 🛡 Security How Obtainium ensures security Mechanism Description Direct download No proxies - file downloads straight from developer\u0026rsquo;s server Signature verification On update, new APK signature is compared with installed one Open source Obtainium code is auditable on GitHub No telemetry App doesn\u0026rsquo;t collect usage data Security recommendations Add only trusted repositories (official developer accounts) Enable \u0026ldquo;Verify signature on update\u0026rdquo; in settings Use Shizuku only with trusted apps Keep Obtainium itself updated Links 📦 Obtainium on F-Droid 🐙 Obtainium on GitHub 🔧 Shizuku on F-Droid 📘 Obtainium Wiki 🔍 Regex tutorial ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/android/obtainium-guide/","summary":"\u003cp\u003eObtainium is an Android update manager that downloads apps \u003cstrong\u003edirectly from developer repositories\u003c/strong\u003e (GitHub, GitLab, Codeberg, F-Droid), bypassing third-party stores.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhy you need it\u003c/strong\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eGet updates faster than Google Play / F-Droid\u003c/li\u003e\n\u003cli\u003eAvoid trackers and ads from third-party stores\u003c/li\u003e\n\u003cli\u003eControl which versions are installed (stable, beta, pre-release)\u003c/li\u003e\n\u003cli\u003eAutomate updates without manual confirmation\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Obtainium doesn\u0026rsquo;t host apps - it only points where to download them. You always know the source.\u003c/p\u003e","title":"Obtainium: App Updates from Source"},{"content":"Shizuku is a service that gives apps access to Android system APIs without root. It works via ADB (Android Debug Bridge), using shell privileges.\nWhy you need it:\nInstall apps without confirmation (Obtainium, SAI) Freeze/unfreeze apps (Ice Box, Hail) Manage permissions (AppOps, Permission Pilot) Change system settings (DarQ, Naptime) Remove system apps (Canta, AppManager) 💡 Shizuku doesn\u0026rsquo;t grant full root - only limited access to system functions. Safer than root, but more powerful than a regular app.\n📦 Installation and setup Step 1: Download Shizuku F-Droid (recommended) GitHub Releases Step 2: Enable Developer Mode Settings → About phone → Tap \u0026ldquo;MIUI version\u0026rdquo; / \u0026ldquo;Build number\u0026rdquo; 7 times Go back to Settings → Additional settings → Developer options Step 3: Enable Wireless Debugging In Developer options → ✅ Wireless debugging Tap \u0026ldquo;Pair device with pairing code\u0026rdquo; → note code and port In Shizuku: \u0026ldquo;Start\u0026rdquo; → \u0026ldquo;Pairing\u0026rdquo; → enter code and port After pairing: \u0026ldquo;Start\u0026rdquo; → service will launch Check status:\nStatus: Running Version: 13.x.x ⚠️ After phone reboot, Shizuku must be restarted manually (process doesn\u0026rsquo;t persist).\n🔧 Example 1: Obtainium + Shizuku Obtainium - app update manager directly from sources (GitHub, GitLab, F-Droid).\nWhy Shizuku for Obtainium Without Shizuku With Shizuku Manual install confirmation Automatic installation Doesn\u0026rsquo;t work with split-APK Supports all formats Requires \u0026ldquo;Unknown sources\u0026rdquo; Installs via system PM Setup Install Obtainium from F-Droid Open Obtainium → Settings → Installation method Select Shizuku (auto-detected if service is running) Add apps to track: Enter repo URL: https://github.com/user/repo Or browse catalog On update: Obtainium downloads → installs via Shizuku → no confirmation needed Example app entry:\nSource: GitHub URL: https://github.com/RikkaApps/Shizuku Filter: Releases (stable) Format: APK 🔧 Example 2: SAI + Shizuku SAI (Split APKs Installer) - installer for split-APK, XAPK, APKS (formats not supported by default installer).\nWhy Shizuku for SAI Without Shizuku With Shizuku Manual confirmation for each APK Batch install without confirmation Doesn\u0026rsquo;t work with some formats Supports all split formats Installation errors Reliable install via system PM Setup Install SAI from F-Droid Open SAI → Settings → Installation method Select Shizuku (or \u0026ldquo;Session API + Shizuku\u0026rdquo; for max compatibility) Install app: Tap \u0026ldquo;Install APK\u0026rdquo; → select .xapk, .apks, .apk file SAI unpacks → installs via Shizuku → done Supported formats:\n.apk - standard package .xapk - APK + OBB data .apks / .apk-m - split-APK (multiple files for different architectures) 🔄 Auto-start Shizuku (optional) After reboot, Shizuku stops. Auto-start options:\nOption 1: Tasker + ADB (no root) # Script for Tasker: start-shizuku.sh adb shell sh /sdcard/Android/data/moe.shizuku.privileged.api/start.sh Setup:\nInstall Tasker Create task → \u0026ldquo;Run Shell\u0026rdquo; → command above Trigger: \u0026ldquo;Device Boot\u0026rdquo; Option 2: KernelSU / Magisk (with root) If rooted - install Shizuku as system app:\nadb push shizuku.apk /data/local/tmp/ adb shell su -c \u0026#34;pm install /data/local/tmp/shizuku.apk\u0026#34; adb shell su -c \u0026#34;sh /sdcard/Android/data/moe.shizuku.privileged.api/start.sh\u0026#34; Benefit: Shizuku starts automatically on boot.\n🔍 Diagnostics # Check if Shizuku is running adb shell sh /sdcard/Android/data/moe.shizuku.privileged.api/start.sh --check # View Shizuku logs adb logcat | grep -i shizuku # Check app access to Shizuku adb shell dumpsys package moe.shizuku.privileged.api | grep -A5 \u0026#34;Granted permissions\u0026#34; ⚠️ Common issues # Shizuku won\u0026#39;t start → Toggle wireless debugging: off → on → Reboot phone and restart Shizuku → Check if antivirus/optimizer is blocking it # Obtainium/SAI don\u0026#39;t detect Shizuku → Ensure service is running (status \u0026#34;Running\u0026#34; in app) → Restart Shizuku and target app → Check permissions: Settings → Apps → [App] → Permissions # \u0026#34;Package parser error\u0026#34; on install → File corrupted - re-download → Unsupported format - check SAI version → Not enough space - clear cache # Shizuku stops by itself → Settings → Battery → [Shizuku] → ✅ No restrictions → Settings → Apps → [Shizuku] → ✅ Auto-start 🛡 Security What can an app do with Shizuku access Action Risk Install/uninstall app Medium (requires user confirmation in Obtainium/SAI) Change permissions Medium (only for own package or with explicit consent) Read logs Low (only own logs) Access files Low (only with explicit permission) How to minimize risks Install Shizuku only from F-Droid or GitHub Grant Shizuku access only to trusted apps (Obtainium, SAI, AppManager) Stop Shizuku when not in use Don\u0026rsquo;t enable wireless debugging on public networks Links 🔧 Shizuku on F-Droid 📦 Obtainium on F-Droid 📱 SAI on F-Droid 📘 Shizuku Documentation 🔐 Android ADB Docs ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/android/shizuku-guide/","summary":"\u003cp\u003eShizuku is a service that gives apps access to Android system APIs \u003cstrong\u003ewithout root\u003c/strong\u003e. It works via ADB (Android Debug Bridge), using \u003ccode\u003eshell\u003c/code\u003e privileges.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhy you need it\u003c/strong\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eInstall apps without confirmation (Obtainium, SAI)\u003c/li\u003e\n\u003cli\u003eFreeze/unfreeze apps (Ice Box, Hail)\u003c/li\u003e\n\u003cli\u003eManage permissions (AppOps, Permission Pilot)\u003c/li\u003e\n\u003cli\u003eChange system settings (DarQ, Naptime)\u003c/li\u003e\n\u003cli\u003eRemove system apps (Canta, AppManager)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Shizuku doesn\u0026rsquo;t grant full root - only limited access to system functions. Safer than root, but more powerful than a regular app.\u003c/p\u003e","title":"Shizuku: Android System Access Without Root"},{"content":"Sometimes you need to run an app on NixOS that\u0026rsquo;s only available for Ubuntu/Debian or ships as .deb/.iso. Distrobox lets you run it in a container with host integration - like a native app.\n💡 Works on any distro with Nix installed.\n📦 Create container # Create container with necessary volume mounts nix shell nixpkgs#distrobox --command distrobox create \\ --image ubuntu:20.04 \\ --name \u0026lt;container-name\u0026gt; \\ --volume \u0026#34;\u0026lt;volume_pts\u0026gt;:/dev/pts\u0026#34; \\ --volume \u0026#34;\u0026lt;volume_journal\u0026gt;:/var/log/journal\u0026#34; \\ --home \u0026#34;$HOME/\u0026lt;container-name\u0026gt;-home\u0026#34; Parameters:\n--image - base image (ubuntu:20.04, debian:11, etc.) --volume - mount directories (audio, logs) --home - separate home directory inside container --name - container name (used in other commands) Enter container:\nnix shell nixpkgs#distrobox --command distrobox enter \u0026lt;container-name\u0026gt; 🔧 Install app inside container # Inside container (after distrobox enter) sudo sh -c \u0026#39; # Clean old configs rm -rf /etc/apt/sources.list.d/\u0026lt;vendor\u0026gt;.list* umount /mnt/\u0026lt;vendor\u0026gt; 2\u0026gt;/dev/null || true # Download and mount image wget -O /tmp/\u0026lt;vendor\u0026gt;.iso \u0026#34;https://\u0026lt;url\u0026gt;/\u0026lt;vendor\u0026gt;.iso\u0026#34; mkdir -p /mnt/\u0026lt;vendor\u0026gt; mount -o loop,ro -t iso9660 /tmp/\u0026lt;vendor\u0026gt;.iso /mnt/\u0026lt;vendor\u0026gt; # Install from local repo echo \u0026#34;deb [trusted=yes] file:/mnt/\u0026lt;vendor\u0026gt;/repo ./\u0026#34; \u0026gt; /etc/apt/sources.list.d/\u0026lt;vendor\u0026gt;.list apt update apt install -y \u0026lt;package-name\u0026gt;-full # Cleanup umount /mnt/\u0026lt;vendor\u0026gt; rm -f /etc/apt/sources.list.d/\u0026lt;vendor\u0026gt;.list /tmp/\u0026lt;vendor\u0026gt;.iso \u0026#39; Replace placeholders:\nPlaceholder Description \u0026lt;vendor\u0026gt; Vendor name (e.g., nausoftphone) \u0026lt;package-name\u0026gt; Package name in repo \u0026lt;url\u0026gt; URL to installer image Verify:\n\u0026lt;package-name\u0026gt; --version 🖥 Desktop launcher (.desktop) # ~/.local/share/applications/\u0026lt;app\u0026gt;-distrobox.desktop [Desktop Entry] Version=1.0 Type=Application Name=\u0026lt;App Name\u0026gt; (Distrobox) Comment=Run \u0026lt;App Name\u0026gt; inside Distrobox container Exec=konsole --hold -e bash -c \u0026#39;nix shell nixpkgs#distrobox --command distrobox enter --name \u0026lt;container-name\u0026gt; -- \u0026lt;app-command\u0026gt;\u0026#39; Icon=\u0026lt;icon-name\u0026gt; Terminal=false Categories=Network;AudioVideo; Keywords=\u0026lt;app\u0026gt;;distrobox;container; Apply:\nupdate-desktop-database ~/.local/share/applications/ App now appears in menu, launchers, and system search.\n🔄 Update app # Enter container nix shell nixpkgs#distrobox --command distrobox enter \u0026lt;container-name\u0026gt; # Upgrade package sudo apt update \u0026amp;\u0026amp; sudo apt install --only-upgrade \u0026lt;package-name\u0026gt;-full 🗑 Full cleanup (container + volumes) # 1. Remove container distrobox rm \u0026lt;container-name\u0026gt; # 2. Remove associated volumes (if created separately) # For Podman: podman volume rm \u0026lt;volume_pts\u0026gt; \u0026lt;volume_journal\u0026gt; # For Docker: docker volume rm \u0026lt;volume_pts\u0026gt; \u0026lt;volume_journal\u0026gt; # 3. Remove container home directory (if used) rm -rf \u0026#34;$HOME/\u0026lt;container-name\u0026gt;-home\u0026#34; # 4. Remove launcher rm -f ~/.local/share/applications/\u0026lt;app\u0026gt;-distrobox.desktop update-desktop-database ~/.local/share/applications/ ⚠️ Volume deletion is irreversible - ensure no needed data inside.\nVerify cleanup:\n# Containers distrobox list | grep \u0026lt;container-name\u0026gt; # Volumes (Podman) podman volume ls | grep \u0026lt;volume_pts\u0026gt; # Volumes (Docker) docker volume ls | grep \u0026lt;volume_pts\u0026gt; ⚙️ Launch optimization Hide terminal (for production) # Replace Exec with: Exec=sh -c \u0026#39;nix shell nixpkgs#distrobox --command distrobox enter --name \u0026lt;container-name\u0026gt; -- \u0026lt;app-command\u0026gt;\u0026#39; \u0026gt;\u0026gt; ~/.cache/\u0026lt;app\u0026gt;.log 2\u0026gt;\u0026amp;1 \u0026amp; Fix audio (if not working) # Add when creating container: --volume \u0026#34;$XDG_RUNTIME_DIR/pulse:/run/user/1000/pulse\u0026#34; # Or for PipeWire: --volume \u0026#34;$XDG_RUNTIME_DIR/pipewire-0:/run/user/1000/pipewire-0\u0026#34; ⚠️ Common issues # Launcher not appearing → Validate syntax: desktop-file-validate ~/.local/share/applications/\u0026lt;app\u0026gt;-distrobox.desktop → Refresh cache: update-desktop-database ~/.local/share/applications/ # Container won\u0026#39;t start after Nix update → Recreate: distrobox rm \u0026lt;name\u0026gt; \u0026amp;\u0026amp; create anew → Data in --home persists if directory not manually deleted # No audio/device access → Check volume mounts during container creation → Ensure user is in required groups (audio, input) # Volume won\u0026#39;t delete (\u0026#34;in use\u0026#34;) → Ensure container is stopped: distrobox list → Force stop: podman stop \u0026lt;container-name\u0026gt; || docker stop \u0026lt;container-name\u0026gt; Links 🐧 Distrobox Docs 🦊 NixOS Wiki: Distrobox 🖥 Desktop Entry Spec ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/linux/nix/distrobox-apps/","summary":"\u003cp\u003eSometimes you need to run an app on NixOS that\u0026rsquo;s only available for Ubuntu/Debian or ships as \u003ccode\u003e.deb\u003c/code\u003e/\u003ccode\u003e.iso\u003c/code\u003e. Distrobox lets you run it in a container with host integration - like a native app.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Works on any distro with Nix installed.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"-create-container\"\u003e📦 Create container\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Create container with necessary volume mounts\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003enix shell nixpkgs#distrobox --command distrobox create \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --image ubuntu:20.04 \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --name \u0026lt;container-name\u0026gt; \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --volume \u003cspan class=\"s2\"\u003e\u0026#34;\u0026lt;volume_pts\u0026gt;:/dev/pts\u0026#34;\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --volume \u003cspan class=\"s2\"\u003e\u0026#34;\u0026lt;volume_journal\u0026gt;:/var/log/journal\u0026#34;\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --home \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$HOME\u003c/span\u003e\u003cspan class=\"s2\"\u003e/\u0026lt;container-name\u0026gt;-home\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eParameters\u003c/strong\u003e:\u003c/p\u003e","title":"NixOS: Running Foreign Apps via Distrobox"},{"content":"Docker Desktop on Windows uses WSL2 with dynamic VHDX files. They grow when adding images/containers but don\u0026rsquo;t shrink automatically when deleting them. Result: C: drive fills up, even though docker system df shows free space.\n💡 Solution: manual VHDX optimization via PowerShell + Docker utility.\n📦 Cleanup script Create file # File: $HOME\\Scripts\\docker-clear-wsl.ps1 $script = @\u0026#39; $LOCAL = \u0026#34;$env:LOCALAPPDATA\\Docker\\wsl\u0026#34; $VHD1 = Join-Path $LOCAL \u0026#34;disk\\docker_data.vhdx\u0026#34; $VHD2 = Join-Path $LOCAL \u0026#34;main\\ext4.vhdx\u0026#34; # 1. Docker cleanup docker system prune -f # 2. Reclaim space via official tool docker run --rm --privileged --pid=host docker/desktop-reclaim-space docker rmi docker/desktop-reclaim-space -f # 3. Stop Docker Desktop Get-Process -Name \u0026#34;Docker Desktop\u0026#34;,\u0026#34;com.docker.backend\u0026#34;,\u0026#34;com.docker.build\u0026#34; ` -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue # 4. Shutdown WSL wsl --shutdown # 5. Optimize VHDX files (compact) if (Test-Path $VHD1) { Optimize-VHD -Path $VHD1 -Mode Full } if (Test-Path $VHD2) { Optimize-VHD -Path $VHD2 -Mode Full } # 6. Restart Docker Desktop Start-Sleep -Seconds 2 Start-Process -FilePath \u0026#34;$env:ProgramFiles\\Docker\\Docker\\Docker Desktop.exe\u0026#34; ` -ErrorAction SilentlyContinue \u0026#39;@ $script | Out-File -FilePath \u0026#34;$HOME\\Scripts\\docker-clear-wsl.ps1\u0026#34; -Encoding UTF8 Run # As Administrator (required for Optimize-VHD) powershell.exe -ExecutionPolicy Bypass -File \u0026#34;$HOME\\Scripts\\docker-clear-wsl.ps1\u0026#34; 🔍 How it works Step Command What it does 1 docker system prune -f Removes stopped containers, unused images, build cache 2 docker/desktop-reclaim-space Official Docker tool to reclaim space in WSL2 3 Stop-Process Gracefully stops Docker Desktop (otherwise VHDX is locked) 4 wsl --shutdown Fully shuts down WSL, freeing files for optimization 5 Optimize-VHD -Mode Full Compacts VHDX files, returning space to host 6 Start-Process Restarts Docker Desktop Why this way:\nWithout stopping processes, Optimize-VHD won\u0026rsquo;t work (file locked) docker/desktop-reclaim-space works inside WSL, removing \u0026ldquo;ghost\u0026rdquo; data Mode Full - maximum compression (slower, but more effective) ⚙️ Automation Via Task Scheduler (GUI) Open Task Scheduler → Create Basic Task Trigger: Weekly (e.g., Sunday, 03:00) Action: Start a program Program: powershell.exe Arguments: -ExecutionPolicy Bypass -File \u0026quot;C:\\Users\\ponfertato\\Scripts\\docker-clear-wsl.ps1\u0026quot; Settings: ✅ Run with highest privileges Via PowerShell (scripted) # Create task as Administrator $action = New-ScheduledTaskAction -Execute \u0026#34;powershell.exe\u0026#34; ` -Argument \u0026#34;-ExecutionPolicy Bypass -File `\u0026#34;$HOME\\Scripts\\docker-clear-wsl.ps1`\u0026#34;\u0026#34; $trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At 3am $principal = New-ScheduledTaskPrincipal -UserId \u0026#34;SYSTEM\u0026#34; -RunLevel Highest Register-ScheduledTask -TaskName \u0026#34;Docker WSL Cleanup\u0026#34; ` -Action $action -Trigger $trigger -Principal $principal Verify and run manually # Run task Start-ScheduledTask -TaskName \u0026#34;Docker WSL Cleanup\u0026#34; # Check status Get-ScheduledTask -TaskName \u0026#34;Docker WSL Cleanup\u0026#34; | Get-ScheduledTaskInfo # View history Get-WinEvent -FilterHashtable @{LogName=\u0026#39;Microsoft-Windows-TaskScheduler/Operational\u0026#39;; TaskName=\u0026#39;Docker WSL Cleanup\u0026#39;} -MaxEvents 10 📊 Monitor results Before and after # VHDX size before cleanup Get-ChildItem \u0026#34;$env:LOCALAPPDATA\\Docker\\wsl\\disk\\docker_data.vhdx\u0026#34; | Select Name, @{N=\u0026#34;SizeGB\u0026#34;;E={[math]::Round($_.Length/1GB,2)}} # After cleanup - compare value Docker stats # Summary docker system df # Detailed docker system df -v Expected result:\ndocker system df shows less data .vhdx file size on disk decreases (sometimes 2-5x) ⚠️ Safety and notes Requirements Requirement Why it matters Run as Administrator Optimize-VHD requires elevated privileges Close WSL-using apps Otherwise wsl --shutdown will fail Backup critical data In case of failure (unlikely, but possible) If something goes wrong # Docker won\u0026#39;t start after cleanup → Launch manually: \u0026#34;$env:ProgramFiles\\Docker\\Docker\\Docker Desktop.exe\u0026#34; → Check logs: Get-Content \u0026#34;$env:LOCALAPPDATA\\Docker\\log.txt\u0026#34; -Tail 50 # VHDX didn\u0026#39;t compact → Ensure Docker and WSL are fully stopped: wsl --list --verbose → Try manually: Optimize-VHD -Path \u0026#34;C:\\path\\to\\docker_data.vhdx\u0026#34; -Mode Full # \u0026#34;Access denied\u0026#34; error → Run PowerShell as Administrator → Check antivirus: may block VHDX access Exclude from cleanup (optional) To preserve specific images:\n# Before prune, tag images docker tag my-important-image my-important-image:keep docker system prune -f --filter \u0026#34;label!=keep\u0026#34; 🗂 Pre-run checklist Closed all apps using Docker/WSL Launched PowerShell as Administrator Checked free space on C: (need ~10% of VHDX size for compaction) Ensured critical data is saved or tagged Tested on one VHDX before full cleanup Links 🐳 Docker Desktop WSL2 Backend 🔧 Optimize-VHD Docs 🗑️ docker system prune 🔄 Reclaim disk space in WSL2 ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/docker/wsl-cleanup/","summary":"\u003cp\u003eDocker Desktop on Windows uses WSL2 with dynamic VHDX files. They \u003cstrong\u003egrow\u003c/strong\u003e when adding images/containers but \u003cstrong\u003edon\u0026rsquo;t shrink automatically\u003c/strong\u003e when deleting them. Result: \u003ccode\u003eC:\u003c/code\u003e drive fills up, even though \u003ccode\u003edocker system df\u003c/code\u003e shows free space.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Solution: manual VHDX optimization via PowerShell + Docker utility.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"-cleanup-script\"\u003e📦 Cleanup script\u003c/h2\u003e\n\u003ch3 id=\"create-file\"\u003eCreate file\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# File: $HOME\\Scripts\\docker-clear-wsl.ps1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003e$script\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"sh\"\u003e@\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e$LOCAL = \u0026#34;$env:LOCALAPPDATA\\Docker\\wsl\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e$VHD1 = Join-Path $LOCAL \u0026#34;disk\\docker_data.vhdx\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e$VHD2 = Join-Path $LOCAL \u0026#34;main\\ext4.vhdx\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e# 1. Docker cleanup\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003edocker system prune -f\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e# 2. Reclaim space via official tool\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003edocker run --rm --privileged --pid=host docker/desktop-reclaim-space\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003edocker rmi docker/desktop-reclaim-space -f\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e# 3. Stop Docker Desktop\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003eGet-Process -Name \u0026#34;Docker Desktop\u0026#34;,\u0026#34;com.docker.backend\u0026#34;,\u0026#34;com.docker.build\u0026#34; `\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e  -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e# 4. Shutdown WSL\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003ewsl --shutdown\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e# 5. Optimize VHDX files (compact)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003eif (Test-Path $VHD1) { Optimize-VHD -Path $VHD1 -Mode Full }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003eif (Test-Path $VHD2) { Optimize-VHD -Path $VHD2 -Mode Full }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e# 6. Restart Docker Desktop\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003eStart-Sleep -Seconds 2\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003eStart-Process -FilePath \u0026#34;$env:ProgramFiles\\Docker\\Docker\\Docker Desktop.exe\u0026#34; `\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e  -ErrorAction SilentlyContinue\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sh\"\u003e\u0026#39;@\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003e$script\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e \u003cspan class=\"nb\"\u003eOut-File\u003c/span\u003e \u003cspan class=\"n\"\u003e-FilePath\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$HOME\u003c/span\u003e\u003cspan class=\"s2\"\u003e\\Scripts\\docker-clear-wsl.ps1\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003e-Encoding\u003c/span\u003e \u003cspan class=\"n\"\u003eUTF8\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"run\"\u003eRun\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# As Administrator (required for Optimize-VHD)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003epowershell\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"py\"\u003eexe\u003c/span\u003e \u003cspan class=\"n\"\u003e-ExecutionPolicy\u003c/span\u003e \u003cspan class=\"n\"\u003eBypass\u003c/span\u003e \u003cspan class=\"o\"\u003e-File\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$HOME\u003c/span\u003e\u003cspan class=\"s2\"\u003e\\Scripts\\docker-clear-wsl.ps1\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"-how-it-works\"\u003e🔍 How it works\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eStep\u003c/th\u003e\n          \u003cth\u003eCommand\u003c/th\u003e\n          \u003cth\u003eWhat it does\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e1\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003edocker system prune -f\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eRemoves stopped containers, unused images, build cache\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e2\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003edocker/desktop-reclaim-space\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eOfficial Docker tool to reclaim space in WSL2\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e3\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eStop-Process\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eGracefully stops Docker Desktop (otherwise VHDX is locked)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e4\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ewsl --shutdown\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eFully shuts down WSL, freeing files for optimization\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e5\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eOptimize-VHD -Mode Full\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eCompacts VHDX files, returning space to host\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e6\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003eStart-Process\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eRestarts Docker Desktop\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003eWhy this way\u003c/strong\u003e:\u003c/p\u003e","title":"Docker WSL: Disk Cleanup \u0026 Optimization"},{"content":"Long-running projects accumulate outdated issues: bugs for old versions, features that are no longer relevant, test tickets. Manual deletion is slow and tedious. This script automatically finds and deletes (or marks) old issues by specified labels.\n💡 Script uses dry-run by default - shows what would be deleted, without actual deletion.\n📦 Script: delete-issues.sh Full code #!/bin/bash # Delete old GitHub Issues by labels and date # Usage: ./delete-issues.sh [--execute] set -euo pipefail # === CONFIG === REPO=\u0026#34;owner/repo\u0026#34; # Repository in owner/repo format LABELS=\u0026#39;label1,label2,label3\u0026#39; # Labels to filter (comma-separated) CUTOFF=\u0026#34;2025-12-31T23:59:59Z\u0026#34; # Delete issues created BEFORE this date DRY_RUN=true # true = preview only, false = actually delete # Parse arguments if [[ \u0026#34;${1:-}\u0026#34; == \u0026#34;--execute\u0026#34; ]]; then DRY_RUN=false echo \u0026#34;⚠️ Mode: ACTUAL DELETION\u0026#34; else echo \u0026#34;ℹ️ Mode: DRY RUN (nothing will be deleted)\u0026#34; fi echo \u0026#34;🔍 Searching issues in $REPO with labels: $LABELS, created before $CUTOFF\u0026#34; echo \u0026#34;---\u0026#34; # Fetch and filter issues gh issue list --repo \u0026#34;$REPO\u0026#34; --state all --limit 1000 \\ --json number,title,createdAt,labels,url | \\ jq -r --arg labels \u0026#34;$LABELS\u0026#34; --arg cutoff \u0026#34;$CUTOFF\u0026#34; \u0026#39; ($labels | split(\u0026#34;,\u0026#34;)) as $label_array | .[] | select(.createdAt \u0026lt; $cutoff) | select(.labels | map(.name) | any(. as $l | $label_array | index($l))) | \u0026#34;\\(.number)|\\(.title)|\\(.url)\u0026#34; \u0026#39; | \\ while IFS=\u0026#39;|\u0026#39; read -r number title url; do if [[ \u0026#34;$DRY_RUN\u0026#34; == \u0026#34;true\u0026#34; ]]; then echo \u0026#34;[DRY RUN] ##$number - $title\u0026#34; echo \u0026#34; $url\u0026#34; else echo \u0026#34;🗑 Deleting ##$number - $title\u0026#34; gh issue delete \u0026#34;$REPO\u0026#34; \u0026#34;$number\u0026#34; --yes sleep 1 # Small pause to avoid rate limits fi done echo \u0026#34;---\u0026#34; echo \u0026#34;✅ Done\u0026#34; Install dependencies # GitHub CLI # Windows (winget): winget install GitHub.cli # Linux (Ubuntu/Debian): sudo apt install gh # macOS (Homebrew): brew install gh # Authenticate gh auth login # jq (JSON processor) # Windows (winget): winget install jq.jq # Linux: sudo apt install jq # macOS: brew install jq Run # Make script executable chmod +x delete-issues.sh # DRY RUN (safe mode - preview only) ./delete-issues.sh # ACTUAL DELETION (add --execute flag) ./delete-issues.sh --execute 🔍 How it works Step-by-step breakdown Step Command What it does 1 gh issue list --json ... Fetches issues as JSON with fields: number, title, date, labels, URL 2 jq -r ... Filters: date \u0026lt; cutoff AND has at least one of specified labels 3 while read ... Processes each matching issue 4 gh issue delete Deletes issue (only if DRY_RUN=false) jq filter logic ($labels | split(\u0026#34;,\u0026#34;)) as $label_array | # Split label string into array .[] | # For each issue select(.createdAt \u0026lt; $cutoff) | # Only if created before cutoff select( .labels | map(.name) | # Get list of label names any(. as $l | $label_array | index($l)) # Check if any matches our labels ) | \u0026#34;\\(.number)|\\(.title)|\\(.url)\u0026#34; # Format output Why this way:\nsplit(\u0026quot;,\u0026quot;) - allows specifying labels as single string any(...) - checks for any of specified labels (logical OR) Pipe-delimited output - reliable way to pass titles with spaces ⚙️ Adapt for your use case Example 1: Delete old bugs REPO=\u0026#34;myorg/myproject\u0026#34; LABELS=\u0026#39;bug,critical\u0026#39; CUTOFF=\u0026#34;2024-01-01T00:00:00Z\u0026#34; # Delete bugs before 2024 Example 2: Close instead of delete Replace deletion block with close:\n# Instead of gh issue delete: echo \u0026#34;🔒 Closing ##$number - $title\u0026#34; gh issue edit \u0026#34;$REPO\u0026#34; \u0026#34;$number\u0026#34; --state closed Example 3: Export before delete (backup) # Add before deletion: echo \u0026#34;💾 Exporting ##$number\u0026#34; gh issue view \u0026#34;$REPO\u0026#34; \u0026#34;$number\u0026#34; --json title,body,comments \u0026gt;\u0026gt; backup-issues.jsonl 🛡 Safety Mandatory checks before running # 1. Verify selected issues are actually the ones you want ./delete-issues.sh | grep -c \u0026#34;\\[DRY RUN\\]\u0026#34; # Count matches # 2. Ensure no critical issues in list ./delete-issues.sh | grep -i \u0026#34;critical\\|important\u0026#34; # 3. Check permissions gh api /repos/$REPO | jq \u0026#39;.permissions.admin\u0026#39; # Should be true GitHub API rate limits Type Limit How to stay under Authenticated 5000 requests/hour sleep 1 between deletions Unauthenticated 60 requests/hour Always use gh auth login Check remaining quota:\ngh api rate_limit | jq \u0026#39;.resources.core\u0026#39; 📊 Alternatives and extensions Preview only (no deletion) gh issue list --repo \u0026#34;$REPO\u0026#34; --state all --limit 1000 \\ --json createdAt,labels | \\ jq -r --arg labels \u0026#34;$LABELS\u0026#34; --arg cutoff \u0026#34;$CUTOFF\u0026#34; \u0026#39; ($labels|split(\u0026#34;,\u0026#34;)) as $label_array | [.[] | select(.createdAt \u0026lt; $cutoff) | select(.labels | map(.name) | any(. as $l | $label_array | index($l)))] | length \u0026#39; Delete by author + labels select(.author.login == \u0026#34;bot-user\u0026#34;) | select(.labels | map(.name) | any(. as $l | $label_array | index($l))) Export to CSV before delete # Add to jq output: \u0026#34;\\(.number),\\\u0026#34;\\(.title)\\\u0026#34;,\\(.createdAt),\\(.url)\u0026#34; ⚠️ Common issues # \u0026#34;gh: command not found\u0026#34; → Install GitHub CLI: https://cli.github.com # \u0026#34;jq: error: syntax error\u0026#34; → Check quotes: use single quotes for jq, double for bash # \u0026#34;HTTP 404: Not Found\u0026#34; → Verify repo name: must be owner/repo → Ensure token has issues:read permission # \u0026#34;rate limit exceeded\u0026#34; → Wait for reset or add delay: sleep 2 # Deleted wrong issues! → Always run without --execute first → Backup first: gh issue list --json ... \u0026gt; backup.json 🗂 Pre-run checklist Installed gh and jq, ran gh auth login Verified repo permissions: gh api /repos/owner/repo Tested in dry-run mode, reviewed issue list Confirmed no critical issues in deletion list Exported backup if needed: gh issue list --json ... \u0026gt; backup.json Only then - run with --execute Links 🐙 GitHub CLI Docs 🔍 gh issue list 🗑️ gh issue delete 🧰 jq Manual 🔐 GitHub API Rate Limits ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/git/delete-issues/","summary":"\u003cp\u003eLong-running projects accumulate outdated issues: bugs for old versions, features that are no longer relevant, test tickets. Manual deletion is slow and tedious. This script automatically finds and deletes (or marks) old issues by specified labels.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Script uses \u003cstrong\u003edry-run by default\u003c/strong\u003e - shows what would be deleted, without actual deletion.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"-script-delete-issuessh\"\u003e📦 Script: delete-issues.sh\u003c/h2\u003e\n\u003ch3 id=\"full-code\"\u003eFull code\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#!/bin/bash\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Delete old GitHub Issues by labels and date\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Usage: ./delete-issues.sh [--execute]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eset\u003c/span\u003e -euo pipefail\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# === CONFIG ===\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eREPO\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;owner/repo\u0026#34;\u003c/span\u003e                              \u003cspan class=\"c1\"\u003e# Repository in owner/repo format\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eLABELS\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;label1,label2,label3\u0026#39;\u003c/span\u003e                  \u003cspan class=\"c1\"\u003e# Labels to filter (comma-separated)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eCUTOFF\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;2025-12-31T23:59:59Z\u0026#34;\u003c/span\u003e                 \u003cspan class=\"c1\"\u003e# Delete issues created BEFORE this date\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eDRY_RUN\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"nb\"\u003etrue\u003c/span\u003e                                   \u003cspan class=\"c1\"\u003e# true = preview only, false = actually delete\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Parse arguments\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"o\"\u003e[[\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nv\"\u003e1\u003c/span\u003e\u003cspan class=\"k\"\u003e:-\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;--execute\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e]]\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"k\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003eDRY_RUN\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;⚠️  Mode: ACTUAL DELETION\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;ℹ️  Mode: DRY RUN (nothing will be deleted)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;🔍 Searching issues in \u003c/span\u003e\u003cspan class=\"nv\"\u003e$REPO\u003c/span\u003e\u003cspan class=\"s2\"\u003e with labels: \u003c/span\u003e\u003cspan class=\"nv\"\u003e$LABELS\u003c/span\u003e\u003cspan class=\"s2\"\u003e, created before \u003c/span\u003e\u003cspan class=\"nv\"\u003e$CUTOFF\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;---\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Fetch and filter issues\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egh issue list --repo \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$REPO\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e --state all --limit \u003cspan class=\"m\"\u003e1000\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --json number,title,createdAt,labels,url \u003cspan class=\"p\"\u003e|\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  jq -r --arg labels \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$LABELS\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e --arg cutoff \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$CUTOFF\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s1\"\u003e    ($labels | split(\u0026#34;,\u0026#34;)) as $label_array |\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s1\"\u003e    .[] |\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s1\"\u003e    select(.createdAt \u0026lt; $cutoff) |\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s1\"\u003e    select(.labels | map(.name) | any(. as $l | $label_array | index($l))) |\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s1\"\u003e    \u0026#34;\\(.number)|\\(.title)|\\(.url)\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s1\"\u003e  \u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"nv\"\u003eIFS\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;|\u0026#39;\u003c/span\u003e \u003cspan class=\"nb\"\u003eread\u003c/span\u003e -r number title url\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"o\"\u003e[[\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$DRY_RUN\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;true\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e]]\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"k\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;[DRY RUN] ##\u003c/span\u003e\u003cspan class=\"nv\"\u003e$number\u003c/span\u003e\u003cspan class=\"s2\"\u003e - \u003c/span\u003e\u003cspan class=\"nv\"\u003e$title\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;          \u003c/span\u003e\u003cspan class=\"nv\"\u003e$url\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;🗑  Deleting ##\u003c/span\u003e\u003cspan class=\"nv\"\u003e$number\u003c/span\u003e\u003cspan class=\"s2\"\u003e - \u003c/span\u003e\u003cspan class=\"nv\"\u003e$title\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      gh issue delete \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$REPO\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$number\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e --yes\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      sleep \u003cspan class=\"m\"\u003e1\u003c/span\u003e  \u003cspan class=\"c1\"\u003e# Small pause to avoid rate limits\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;---\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;✅ Done\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"install-dependencies\"\u003eInstall dependencies\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# GitHub CLI\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Windows (winget):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ewinget install GitHub.cli\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Linux (Ubuntu/Debian):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install gh\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# macOS (Homebrew):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ebrew install gh\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Authenticate\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egh auth login\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# jq (JSON processor)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Windows (winget):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ewinget install jq.jq\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Linux:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install jq\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# macOS:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ebrew install jq\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"run\"\u003eRun\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Make script executable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003echmod +x delete-issues.sh\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# DRY RUN (safe mode - preview only)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e./delete-issues.sh\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# ACTUAL DELETION (add --execute flag)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e./delete-issues.sh --execute\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"-how-it-works\"\u003e🔍 How it works\u003c/h2\u003e\n\u003ch3 id=\"step-by-step-breakdown\"\u003eStep-by-step breakdown\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eStep\u003c/th\u003e\n          \u003cth\u003eCommand\u003c/th\u003e\n          \u003cth\u003eWhat it does\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e1\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003egh issue list --json ...\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eFetches issues as JSON with fields: number, title, date, labels, URL\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e2\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ejq -r ...\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eFilters: date \u0026lt; cutoff AND has at least one of specified labels\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e3\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003ewhile read ...\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eProcesses each matching issue\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e4\u003c/td\u003e\n          \u003ctd\u003e\u003ccode\u003egh issue delete\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eDeletes issue (only if \u003ccode\u003eDRY_RUN=false\u003c/code\u003e)\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"jq-filter-logic\"\u003ejq filter logic\u003c/h3\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode class=\"language-jq\" data-lang=\"jq\"\u003e($labels | split(\u0026#34;,\u0026#34;)) as $label_array |  # Split label string into array\n.[] |                                      # For each issue\nselect(.createdAt \u0026lt; $cutoff) |            # Only if created before cutoff\nselect(\n  .labels | map(.name) |                  # Get list of label names\n  any(. as $l | $label_array | index($l)) # Check if any matches our labels\n) |\n\u0026#34;\\(.number)|\\(.title)|\\(.url)\u0026#34;            # Format output\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003eWhy this way\u003c/strong\u003e:\u003c/p\u003e","title":"GitHub CLI: Bulk Delete Old Issues"},{"content":"For home servers and test environments, resource saving is important: containers can be stopped and system powered off during nights or off-hours. This guide describes a safe method with state preservation and automatic recovery.\n💡 Method suits OrangePI, Raspberry Pi, old PCs, and any systems where power efficiency matters.\n📦 Container shutdown script Create script # File: /usr/local/bin/stop_containers_and_shutdown.sh cat \u0026gt; /usr/local/bin/stop_containers_and_shutdown.sh \u0026lt;\u0026lt; \u0026#39;EOF\u0026#39; #!/bin/bash # # Script saves running container IDs, # stops them, and initiates system shutdown. # CONTAINERS_FILE=\u0026#34;/etc/active_containers.txt\u0026#34; echo \u0026#34;=== $(date \u0026#39;+%Y-%m-%d %H:%M:%S\u0026#39;) ===\u0026#34; echo \u0026#34;Starting container shutdown and system power-off script\u0026#34; # Get list of running containers (by ID) RUNNING_CONTAINERS=$(docker ps -q) if [ -n \u0026#34;${RUNNING_CONTAINERS}\u0026#34; ]; then echo \u0026#34;Saving running containers to ${CONTAINERS_FILE}\u0026#34; echo \u0026#34;${RUNNING_CONTAINERS}\u0026#34; \u0026gt; \u0026#34;${CONTAINERS_FILE}\u0026#34; docker stop ${RUNNING_CONTAINERS} echo \u0026#34;Containers stopped.\u0026#34; else echo \u0026#34;No running containers.\u0026#34; [ -f \u0026#34;${CONTAINERS_FILE}\u0026#34; ] \u0026amp;\u0026amp; rm -f \u0026#34;${CONTAINERS_FILE}\u0026#34; fi sleep 10 echo \u0026#34;Shutting down system.\u0026#34; /sbin/shutdown -h now EOF Make executable chmod +x /usr/local/bin/stop_containers_and_shutdown.sh How it works Step Description docker ps -q Gets IDs of all running containers \u0026gt; /etc/active_containers.txt Saves list for recovery docker stop Gracefully stops containers (SIGTERM) sleep 10 Allows time for operations to complete shutdown -h now Powers off the system Why this way:\nSaving IDs allows restoring the same containers docker stop gives containers time for graceful shutdown sleep 10 ensures all data is written to disk 🚀 Container startup script Create script # File: /usr/local/bin/start_containers.sh cat \u0026gt; /usr/local/bin/start_containers.sh \u0026lt;\u0026lt; \u0026#39;EOF\u0026#39; #!/bin/bash # # Script reads container list from file, # starts them, then removes the file. # CONTAINERS_FILE=\u0026#34;/etc/active_containers.txt\u0026#34; echo \u0026#34;=== $(date \u0026#39;+%Y-%m-%d %H:%M:%S\u0026#39;) ===\u0026#34; echo \u0026#34;Starting container startup script\u0026#34; if [ ! -f \u0026#34;${CONTAINERS_FILE}\u0026#34; ]; then echo \u0026#34;File ${CONTAINERS_FILE} not found. No startup needed.\u0026#34; exit 0 fi CONTAINERS=$(cat \u0026#34;${CONTAINERS_FILE}\u0026#34;) if [ -n \u0026#34;${CONTAINERS}\u0026#34; ]; then echo \u0026#34;Found container list: ${CONTAINERS}\u0026#34; for cid in ${CONTAINERS}; do docker start \u0026#34;${cid}\u0026#34; if [ $? -eq 0 ]; then echo \u0026#34;Container ${cid} started.\u0026#34; else echo \u0026#34;Error starting container ${cid}.\u0026#34; fi done else echo \u0026#34;File empty. No containers to start.\u0026#34; fi rm -f \u0026#34;${CONTAINERS_FILE}\u0026#34; echo \u0026#34;File ${CONTAINERS_FILE} removed.\u0026#34; EOF Make executable chmod +x /usr/local/bin/start_containers.sh How it works Step Description File check If missing - containers weren\u0026rsquo;t stopped by script docker start Starts containers by saved IDs rm -f Removes file after successful startup Why remove file:\nOne-time marker - containers won\u0026rsquo;t restart accidentally After reboot without script - system runs in normal mode ⏰ Schedule setup (cron) Shutdown (night) # crontab -e (as root) # Shutdown at 00:00 daily 0 0 * * * /usr/local/bin/stop_containers_and_shutdown.sh \u0026gt;\u0026gt; /var/log/docker-shutdown.log 2\u0026gt;\u0026amp;1 Startup (morning) # crontab -e (as root) # Startup at 08:00 daily 0 8 * * * /usr/local/bin/start_containers.sh \u0026gt;\u0026gt; /var/log/docker-startup.log 2\u0026gt;\u0026amp;1 Important notes Parameter Description \u0026gt;\u0026gt; /var/log/... Logging for debugging 2\u0026gt;\u0026amp;1 Redirect errors to same log As root Required for docker and shutdown Verify cron:\n# Ensure cron is running systemctl status cron # View logs tail -f /var/log/docker-shutdown.log tail -f /var/log/docker-startup.log 🔧 Alternative: systemd timer (modern method) Shutdown timer # /etc/systemd/system/docker-shutdown.timer [Unit] Description=Daily Docker shutdown timer [Timer] OnCalendar=*-*-* 00:00:00 Persistent=true [Install] WantedBy=timers.target Shutdown service # /etc/systemd/system/docker-shutdown.service [Unit] Description=Stop Docker containers and shutdown After=docker.service [Service] Type=oneshot ExecStart=/usr/local/bin/stop_containers_and_shutdown.sh Activate systemctl daemon-reload systemctl enable docker-shutdown.timer systemctl start docker-shutdown.timer # Check status systemctl list-timers | grep docker-shutdown systemd timer advantages:\nPrecise timing (not affected by cron load) Built-in logging via journalctl Persistent=true - runs missed execution after downtime 🛡 Safety and reliability Exclude critical containers If some containers must run continuously:\n# Modify shutdown script RUNNING_CONTAINERS=$(docker ps -q --filter \u0026#34;label=shutdown=false\u0026#34;) # In docker-compose.yml add label services: critical-service: image: ... labels: - \u0026#34;shutdown=false\u0026#34; Pre-shutdown check # Add to shutdown script ACTIVE_CONNECTIONS=$(netstat -an | grep ESTABLISHED | wc -l) if [ \u0026#34;$ACTIVE_CONNECTIONS\u0026#34; -gt 10 ]; then echo \u0026#34;Active connections detected. Cancelling shutdown.\u0026#34; exit 1 fi UPS integration # Integration with NUT (Network UPS Tools) # /etc/nut/upsmon.conf MONITOR ups@localhost 1 admin password slave SHUTDOWNCMD \u0026#34;/usr/local/bin/stop_containers_and_shutdown.sh\u0026#34; 📊 Monitoring and debugging Check logs # Script logs tail -50 /var/log/docker-shutdown.log tail -50 /var/log/docker-startup.log # Systemd logs (if used) journalctl -u docker-shutdown.service -n 50 journalctl -u docker-startup.service -n 50 Check status # Which containers are running docker ps --format \u0026#34;table {{.Names}}\\t{{.Status}}\u0026#34; # Timer status systemctl list-timers | grep docker # State file (if exists) cat /etc/active_containers.txt 2\u0026gt;/dev/null || echo \u0026#34;File not found\u0026#34; ⚠️ Common issues # Script not running via cron → Check permissions: ls -la /usr/local/bin/*.sh → Check cron: grep CRON /var/log/syslog → Ensure cron is running: systemctl status cron # Containers not starting → Check Docker: systemctl status docker → Check logs: docker logs \u0026lt;container_id\u0026gt; → Verify file exists: cat /etc/active_containers.txt # System not shutting down → Check shutdown available: which shutdown → Check permissions: script must run as root → View logs: journalctl -b -1 (previous boot) # File not removed after startup → Check file permissions: ls -la /etc/active_containers.txt → Remove manually: rm -f /etc/active_containers.txt 🗂 Pre-deployment checklist Tested scripts manually before cron setup Verified logging: /var/log/docker-*.log Ensured critical services excluded (if needed) Confirmed container data on persistent volumes Configured startup/shutdown notifications (optional) Created config backup Links 🐳 Docker Start/Stop Docs ⏰ Cron Documentation 🔧 Systemd Timer Docs 🛡 NUT - UPS Management ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/docker/scheduled-shutdown/","summary":"\u003cp\u003eFor home servers and test environments, resource saving is important: containers can be stopped and system powered off during nights or off-hours. This guide describes a safe method with state preservation and automatic recovery.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Method suits OrangePI, Raspberry Pi, old PCs, and any systems where power efficiency matters.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"-container-shutdown-script\"\u003e📦 Container shutdown script\u003c/h2\u003e\n\u003ch3 id=\"create-script\"\u003eCreate script\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# File: /usr/local/bin/stop_containers_and_shutdown.sh\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecat \u0026gt; /usr/local/bin/stop_containers_and_shutdown.sh \u003cspan class=\"s\"\u003e\u0026lt;\u0026lt; \u0026#39;EOF\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e#!/bin/bash\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e# Script saves running container IDs,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e# stops them, and initiates system shutdown.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e#\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eCONTAINERS_FILE=\u0026#34;/etc/active_containers.txt\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eecho \u0026#34;=== $(date \u0026#39;+%Y-%m-%d %H:%M:%S\u0026#39;) ===\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eecho \u0026#34;Starting container shutdown and system power-off script\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e# Get list of running containers (by ID)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eRUNNING_CONTAINERS=$(docker ps -q)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eif [ -n \u0026#34;${RUNNING_CONTAINERS}\u0026#34; ]; then\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    echo \u0026#34;Saving running containers to ${CONTAINERS_FILE}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    echo \u0026#34;${RUNNING_CONTAINERS}\u0026#34; \u0026gt; \u0026#34;${CONTAINERS_FILE}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    docker stop ${RUNNING_CONTAINERS}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    echo \u0026#34;Containers stopped.\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eelse\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    echo \u0026#34;No running containers.\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    [ -f \u0026#34;${CONTAINERS_FILE}\u0026#34; ] \u0026amp;\u0026amp; rm -f \u0026#34;${CONTAINERS_FILE}\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003efi\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003esleep 10\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eecho \u0026#34;Shutting down system.\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e/sbin/shutdown -h now\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eEOF\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"make-executable\"\u003eMake executable\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003echmod +x /usr/local/bin/stop_containers_and_shutdown.sh\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"how-it-works\"\u003eHow it works\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eStep\u003c/th\u003e\n          \u003cth\u003eDescription\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003edocker ps -q\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eGets IDs of all running containers\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e\u0026gt; /etc/active_containers.txt\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eSaves list for recovery\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003edocker stop\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eGracefully stops containers (SIGTERM)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003esleep 10\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eAllows time for operations to complete\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003eshutdown -h now\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003ePowers off the system\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003eWhy this way\u003c/strong\u003e:\u003c/p\u003e","title":"Docker: Scheduled Automatic Shutdown"},{"content":"Docker Volumes store data independently from containers but require separate approach for backup. This guide describes universal methods for working with volumes using popular services as examples.\n💡 Replace volume names with your own. Methods work with any containers.\n📦 Backup volumes Via docker-volume-backup (recommended) docker run --rm \\ -v portainer_data:/backup/portainer_data \\ -v postgres_data:/backup/postgres_data \\ -v redis_data:/backup/redis_data \\ -v /opt/docker/backup:/archive \\ --entrypoint backup \\ offen/docker-volume-backup:v2 Parameters:\nParameter Description -v \u0026lt;volume\u0026gt;:/backup/\u0026lt;name\u0026gt; Map volume to backup directory -v /opt/docker/backup:/archive Where to save archive on host --entrypoint backup Run backup mode --rm Remove container after completion Why this method:\n✅ One container - all volumes ✅ Automatic tar.gz compression ✅ No service stop required (for most scenarios) ✅ Suitable for cron automation Alternative: via tar directly # Single volume backup docker run --rm \\ -v postgres_data:/volume:ro \\ -v /opt/docker/backup:/backup \\ alpine tar czf /backup/postgres-$(date +%F).tar.gz -C /volume . Features:\n:ro - read-only, protects from modification during backup Direct archive creation without intermediate scripts Suitable for one-time operations 🔄 Restore from backup Step 1: Extract archive tar -C /tmp -xvf backup-*.tar.gz Step 2: Copy data to volumes # Portainer docker run -d --name tmp-portainer -v portainer_data:/restore alpine docker cp /tmp/backup/portainer_data tmp-portainer:/restore docker stop tmp-portainer \u0026amp;\u0026amp; docker rm tmp-portainer # PostgreSQL docker run -d --name tmp-postgres -v postgres_data:/restore alpine docker cp /tmp/backup/postgres_data tmp-postgres:/restore docker stop tmp-postgres \u0026amp;\u0026amp; docker rm tmp-postgres # Redis docker run -d --name tmp-redis -v redis_data:/restore alpine docker cp /tmp/backup/redis_data tmp-redis:/restore docker stop tmp-redis \u0026amp;\u0026amp; docker rm tmp-redis Why via temporary containers:\nDirect volume access from host is complex (path in /var/lib/docker/volumes/) docker cp preserves file permissions and attributes Containers removed after copy - clean and safe Recommendation # Stop services before restore docker compose stop postgres redis portainer # Perform restore # Start services docker compose start 🔀 Migrate volumes Copy to new volume docker volume create new_volume \u0026amp;\u0026amp; \\ docker run --rm -it \\ -v old_volume:/from \\ -v new_volume:/to \\ alpine ash -c \u0026#39;cd /from \u0026amp;\u0026amp; cp -av . /to\u0026#39; Breakdown:\ndocker volume create - creates target volume -v old_volume:/from - mounts source -v new_volume:/to - mounts destination cp -av - copies with preserved permissions (-a) and progress (-v) When to use:\nRenaming volume Migrating to different storage driver Cleaning from temp files (copy only needed data) Cross-host migration # Source host: create archive docker run --rm \\ -v postgres_data:/data \\ -v /backup:/archive \\ alpine tar czf /archive/postgres.tar.gz -C /data . # Copy to new host scp /backup/postgres.tar.gz user@newhost:/backup/ # New host: restore docker volume create postgres_data docker run --rm \\ -v postgres_data:/data \\ -v /backup:/archive \\ alpine tar xzf /archive/postgres.tar.gz -C /data Advantages:\nTransfers all data and permissions Independent of Docker versions Works over any network (SCP, rsync, HTTPS) 🛠 Automation Via cron on host # /etc/crontabs/root - daily backup at 03:00 0 3 * * * docker run --rm -v postgres_data:/backup/data -v /opt/backup:/archive --entrypoint backup offen/docker-volume-backup:v2 Via Docker Compose version: \u0026#34;3.8\u0026#34; services: backup: image: offen/docker-volume-backup:v2 container_name: volume-backup environment: BACKUP_CRON_EXPRESSION: \u0026#34;0 3 * * *\u0026#34; BACKUP_RETENTION_DAYS: \u0026#34;7\u0026#34; volumes: - postgres_data:/backup/postgres_data - redis_data:/backup/redis_data - /opt/backup:/archive entrypoint: [\u0026#34;/bin/sh\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#34;backup\u0026#34;] Features:\nBuilt-in backup rotation Logging inside container S3-compatible storage support 📊 Integrity verification # After backup: verify archive tar -tzf backup-*.tar.gz | head -20 sha256sum backup-*.tar.gz \u0026gt; backup.sha256 # After restore: verify data docker system df -v | grep postgres_data docker logs postgres --tail 50 ⚠️ Common issues # \u0026#34;volume not found\u0026#34; → docker volume ls | grep \u0026lt;name\u0026gt; → docker volume inspect \u0026lt;name\u0026gt; # \u0026#34;permission denied\u0026#34; → Run as root or with sudo → Check permissions: ls -la /opt/docker/backup/ # Backup too large → Exclude cache: tar --exclude=\u0026#39;cache/*\u0026#39; ... → Configure rotation: BACKUP_RETENTION_DAYS=7 # Restore not working → Stop service: docker stop \u0026lt;container\u0026gt; → Check volume not in use: docker ps --filter volume=\u0026lt;name\u0026gt; 🗂 Checklist Before backup Checked space: df -h /opt/docker/backup Stopped DB and critical services Tested on one volume Before restore Stopped target containers Verified archive: tar -tzf backup.tar.gz Prepared rollback plan Links 🐳 Docker Volumes Docs 🔄 offen/docker-volume-backup 📦 Docker Compose Production ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/docker/volumes-management/","summary":"\u003cp\u003eDocker Volumes store data independently from containers but require separate approach for backup. This guide describes universal methods for working with volumes using popular services as examples.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Replace volume names with your own. Methods work with any containers.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"-backup-volumes\"\u003e📦 Backup volumes\u003c/h2\u003e\n\u003ch3 id=\"via-docker-volume-backup-recommended\"\u003eVia docker-volume-backup (recommended)\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edocker run --rm \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  -v portainer_data:/backup/portainer_data \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  -v postgres_data:/backup/postgres_data \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  -v redis_data:/backup/redis_data \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  -v /opt/docker/backup:/archive \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --entrypoint backup \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  offen/docker-volume-backup:v2\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eParameters\u003c/strong\u003e:\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eParameter\u003c/th\u003e\n          \u003cth\u003eDescription\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e-v \u0026lt;volume\u0026gt;:/backup/\u0026lt;name\u0026gt;\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eMap volume to backup directory\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e-v /opt/docker/backup:/archive\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eWhere to save archive on host\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e--entrypoint backup\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eRun backup mode\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003ccode\u003e--rm\u003c/code\u003e\u003c/td\u003e\n          \u003ctd\u003eRemove container after completion\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e\u003cstrong\u003eWhy this method\u003c/strong\u003e:\u003c/p\u003e","title":"Docker Volumes: Backup \u0026 Migration"},{"content":"A submodule is a reference to another Git repository inside your project. Useful when you need to include an external library or shared code, but keep it in a separate repo.\n💡 A submodule stores not the code, but a reference to a specific commit of the external repo.\nAdd a submodule # Add a repo as a submodule to a specific path git submodule add \u0026lt;URL\u0026gt; \u0026lt;path/to/place\u0026gt; # Example git submodule add https://github.com/luizdepra/hugo-coder.git themes/hugo-coder # Commit changes git commit -m \u0026#34;Add submodule: themes/hugo-coder\u0026#34; git push After this, your project will have:\n.gitmodules file - submodule configuration Submodule folder - a reference to the external repo Clone a project with submodules # Option 1: clone with submodules from the start git clone --recursive \u0026lt;URL\u0026gt; # Option 2: if you already cloned without submodules git submodule update --init --recursive Update a submodule # Go into the submodule and pull changes cd themes/hugo-coder git pull origin main # Go back to root and commit the new submodule commit cd ../.. git add themes/hugo-coder git commit -m \u0026#34;Update submodule: hugo-coder\u0026#34; git push Or one command from root:\n# Update all submodules to latest remote commits git submodule update --init --recursive --remote # Commit the updated references git add . git commit -m \u0026#34;Update all submodules\u0026#34; git push ⚠️ --remote fetches latest commits from remote repos. Without it, only commits already recorded in .gitmodules are used.\nRemove a submodule # 1. Deinitialize the submodule git submodule deinit -f themes/hugo-coder # 2. Remove from index and working directory git rm -f themes/hugo-coder # 3. Remove internal data (optional but recommended) rm -rf .git/modules/themes/hugo-coder # 4. Commit changes git commit -m \u0026#34;Remove submodule: themes/hugo-coder\u0026#34; git push Useful commands # Show status of all submodules git submodule status # Show which commits are pending update git submodule foreach \u0026#39;git log -1 --oneline\u0026#39; # Sync submodule URLs (if remote changed) git submodule sync --recursive # Run a command in all submodules git submodule foreach \u0026#39;git fetch\u0026#39; Troubleshooting # Submodule folder is empty after clone → git submodule update --init --recursive # \u0026#34;fatal: not a git repository\u0026#34; inside submodule → Delete the submodule folder and run: git submodule update --init # Submodule version conflict during merge → Choose the correct commit version: git add themes/hugo-coder git commit -m \u0026#34;Resolve submodule conflict\u0026#34; Links 📘 Official Git Book: Submodules 🐙 git-submodule docs ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/git/submodules/","summary":"\u003cp\u003eA submodule is a reference to another Git repository inside your project. Useful when you need to include an external library or shared code, but keep it in a separate repo.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 A submodule stores not the code, but a \u003cstrong\u003ereference to a specific commit\u003c/strong\u003e of the external repo.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"add-a-submodule\"\u003eAdd a submodule\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Add a repo as a submodule to a specific path\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit submodule add \u0026lt;URL\u0026gt; \u0026lt;path/to/place\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Example\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit submodule add https://github.com/luizdepra/hugo-coder.git themes/hugo-coder\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Commit changes\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit commit -m \u003cspan class=\"s2\"\u003e\u0026#34;Add submodule: themes/hugo-coder\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit push\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAfter this, your project will have:\u003c/p\u003e","title":"Git Submodules: Cheat Sheet"},{"content":"Git is a version control system. It tracks code changes, enables team collaboration, and lets you undo mistakes.\n💡 Install once, use for years.\nInstallation Windows Option 1: Official installer (recommended)\nDownload from git-scm.com Run installer, keep defaults Important: On \u0026ldquo;Adjusting your PATH\u0026rdquo; step, select Git from the command line and also from 3rd-party software Option 2: Via Winget (PowerShell)\nwinget install Git.Git Option 3: Via Chocolatey\nchoco install git -y Linux Ubuntu / Debian\nsudo apt update sudo apt install git -y Fedora / RHEL\nsudo dnf install git -y Arch / Manjaro\nsudo pacman -S git Verify installation (all systems)\ngit --version # Expected: git version 2.x.x Basic configuration # Name and email (appear in every commit) git config --global user.name \u0026#34;Kirill Ponfertato\u0026#34; git config --global user.email \u0026#34;kirill@potatoenergy.ru\u0026#34; # Default editor (pick one) git config --global core.editor \u0026#34;code --wait\u0026#34; # VS Code git config --global core.editor \u0026#34;nano\u0026#34; # Nano git config --global core.editor \u0026#34;vim\u0026#34; # Vim # Default branch name git config --global init.defaultBranch main # Colored output git config --global color.ui auto # Auto CRLF for line endings git config --global core.autocrlf true # Windows git config --global core.autocrlf input # Linux/macOS # View all settings git config --global --list SSH keys (for GitHub / GitLab) # Generate key (press Enter for all prompts) ssh-keygen -t ed25519 -C \u0026#34;kirill@potatoenergy.ru\u0026#34; # If ed25519 not supported: ssh-keygen -t rsa -b 4096 -C \u0026#34;kirill@potatoenergy.ru\u0026#34; # Start SSH agent and add key eval \u0026#34;$(ssh-agent -s)\u0026#34; ssh-add ~/.ssh/id_ed25519 # Show public key (copy the output) cat ~/.ssh/id_ed25519.pub # Windows (PowerShell): Get-Content ~/.ssh/id_ed25519.pub # Add key to: # • GitHub: Settings → SSH and GPG keys → New SSH key # • GitLab: User Settings → SSH Keys Test connection\n# GitHub ssh -T git@github.com # Expected: \u0026#34;Hi ponfertato! You\u0026#39;ve successfully authenticated\u0026#34; # GitLab ssh -T git@gitlab.com First steps # Create new repository mkdir my-project \u0026amp;\u0026amp; cd my-project git init # Clone existing one git clone \u0026lt;URL\u0026gt; git clone \u0026lt;URL\u0026gt; my-folder # into named folder git clone --depth 1 \u0026lt;URL\u0026gt; # only latest commit # Check status git status # Add files and commit git add . git commit -m \u0026#34;Initial commit\u0026#34; # Connect remote repository git remote add origin git@github.com:ponfertato/my-project.git git push -u origin main Useful aliases (optional) # Add to ~/.gitconfig or run commands: git config --global alias.co checkout git config --global alias.br branch git config --global alias.ci commit git config --global alias.st \u0026#34;status -s\u0026#34; git config --global alias.lg \u0026#34;log --oneline --graph --all\u0026#34; # Usage: git st # instead of git status -s git lg # pretty log git co -b feature # create and switch to branch Troubleshooting # Git not found after install → Restart terminal / computer # \u0026#34;Permission denied (publickey)\u0026#34; error → Ensure public key is added to GitHub/GitLab profile → Test: ssh -T git@github.com # Line ending conflicts (CRLF/LF) → Set core.autocrlf for your OS (see above) # Reset all config to defaults git config --global --unset-all user.name git config --global --unset-all user.email # Or delete: ~/.gitconfig Links 🌐 Official site 📘 Pro Git book (free) 🎮 Interactive tutorial 🔑 .gitignore generator ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/git/install/","summary":"\u003cp\u003eGit is a version control system. It tracks code changes, enables team collaboration, and lets you undo mistakes.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Install once, use for years.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"installation\"\u003eInstallation\u003c/h2\u003e\n\u003ch3 id=\"windows\"\u003eWindows\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eOption 1: Official installer (recommended)\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eDownload from \u003ca href=\"https://git-scm.com/download/win\"\u003egit-scm.com\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eRun installer, keep defaults\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eImportant\u003c/strong\u003e: On \u0026ldquo;Adjusting your PATH\u0026rdquo; step, select \u003ccode\u003eGit from the command line and also from 3rd-party software\u003c/code\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eOption 2: Via Winget (PowerShell)\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ewinget\u003c/span\u003e \u003cspan class=\"n\"\u003einstall\u003c/span\u003e \u003cspan class=\"n\"\u003eGit\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"py\"\u003eGit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eOption 3: Via Chocolatey\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003echoco\u003c/span\u003e \u003cspan class=\"n\"\u003einstall\u003c/span\u003e \u003cspan class=\"n\"\u003egit\u003c/span\u003e \u003cspan class=\"n\"\u003e-y\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"linux\"\u003eLinux\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eUbuntu / Debian\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt update\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install git -y\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eFedora / RHEL\u003c/strong\u003e\u003c/p\u003e","title":"Git: Installation \u0026 Setup"},{"content":"GPT4Free (g4f) is a free tool that gives you access to powerful AI models: GPT-4/5, Claude, Gemini, DeepSeek. It works by reverse-engineering public APIs.\n⚠️ Note: For educational and testing purposes only. May violate some services\u0026rsquo; ToS.\nInstall in 2 minutes Requirements Any computer with internet Python 3.10+ (check \u0026ldquo;Add to PATH\u0026rdquo; during install) One command pip install -U g4f[all] Done. Library is ready.\nRun it Option 1: Web UI (chat in your browser) python -m g4f.cli gui --port 8080 Open in browser: http://localhost:8080/chat/\nOption 2: Developer mode (local API) python -m g4f --port 1337 Now you can connect any app that supports OpenAI API.\nYour first script: 5 lines Create test.py:\nfrom g4f.client import Client client = Client() response = client.chat.completions.create( model=\u0026#34;gpt-4o-mini\u0026#34;, messages=[{\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;Why is potato a state of mind?\u0026#34;}] ) print(response.choices[0].message.content) Run it:\npython test.py Generate images from g4f.client import Client client = Client() img = client.images.generate( model=\u0026#34;flux\u0026#34;, prompt=\u0026#34;Cyberpunk potato in a neon city\u0026#34;, response_format=\u0026#34;url\u0026#34; ) print(f\u0026#34;Done: {img.data[0].url}\u0026#34;) Working models (March 2026) Model Status Best for gpt-4o-mini ✅ Stable Fast chat, quick answers gpt-4o ✅ Stable Complex tasks, reasoning deepseek-v3 ✅ Stable Code, math, logic gemini-2.5-pro ⚠️ Intermittent Multimodal tasks llama-3.3-70b ✅ Stable Open-source alternative gpt-5 🔶 Experimental May not work 💡 List changes often. Get the live list via:\nGET http://localhost:8080/backend-api/models\nConnect to any OpenAI-compatible app After running python -m g4f --port 1337:\nfrom openai import OpenAI client = OpenAI( base_url=\u0026#34;http://localhost:1337/v1\u0026#34;, api_key=\u0026#34;doesnt-matter\u0026#34; # any value works ) response = client.chat.completions.create( model=\u0026#34;gpt-4o-mini\u0026#34;, messages=[{\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;Tell me a potato joke\u0026#34;}] ) print(response.choices[0].message.content) Works with LibreChat, Flowise, AnythingLLM, and more.\nTroubleshooting # Update the library pip install -U g4f # Install errors on Windows pip install --upgrade pip setuptools wheel # Model not responding # → Try a different model # → Enable VPN # → Wait 10-30 seconds (some providers are slow) # Using Docker? Give the browser more shared memory: docker run -p 8080:8080 --shm-size=\u0026#34;2g\u0026#34; hlohaus789/g4f:latest Docker (for servers \u0026amp; advanced users) docker run -p 8080:8080 --shm-size=\u0026#34;2g\u0026#34; hlohaus789/g4f:latest Web UI: http://localhost:8080 API: http://localhost:8080/v1 Links 🐍 Official repo 📦 Docker image 🌐 Docs 💬 Telegram channel ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/gpt/gpt4free/","summary":"\u003cp\u003eGPT4Free (g4f) is a free tool that gives you access to powerful AI models: GPT-4/5, Claude, Gemini, DeepSeek. It works by reverse-engineering public APIs.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e⚠️ \u003cstrong\u003eNote\u003c/strong\u003e: For educational and testing purposes only. May violate some services\u0026rsquo; ToS.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"install-in-2-minutes\"\u003eInstall in 2 minutes\u003c/h2\u003e\n\u003ch3 id=\"requirements\"\u003eRequirements\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eAny computer with internet\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://python.org\"\u003ePython 3.10+\u003c/a\u003e (check \u0026ldquo;Add to PATH\u0026rdquo; during install)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"one-command\"\u003eOne command\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003epip install -U g4f\u003cspan class=\"o\"\u003e[\u003c/span\u003eall\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eDone. Library is ready.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"run-it\"\u003eRun it\u003c/h2\u003e\n\u003ch3 id=\"option-1-web-ui-chat-in-your-browser\"\u003eOption 1: Web UI (chat in your browser)\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003epython -m g4f.cli gui --port \u003cspan class=\"m\"\u003e8080\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eOpen in browser: \u003ccode\u003ehttp://localhost:8080/chat/\u003c/code\u003e\u003c/p\u003e","title":"GPT4Free in 2026: A complete guide to free access to GPT-5, DeepSeek and Gemini"},{"content":"OpenSSH is a tool for secure remote access via the SSH protocol. It encrypts all traffic, supports key-based authentication, and works on Windows, Linux, and macOS.\n💡 After setup, you can connect to your Windows PC like a Linux server: ssh user@192.168.1.100\nRequirements OS: Windows 10 (1809+), Windows 11, Windows Server 2019/2022 Privileges: Administrator Network: Access to port 22 (local or remote) Installation (3 ways) Option 1: PowerShell (recommended) # Run as Administrator # Install OpenSSH server Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 # Verify installation Get-WindowsCapability -Online | Where-Object Name -like \u0026#39;OpenSSH*\u0026#39; Option 2: DISM (alternative) dism /Online /Add-Capability /CapabilityName:OpenSSH.Server~~~~0.0.1.0 Option 3: Via Settings (GUI) Settings → Apps → Optional features \u0026ldquo;Add a feature\u0026rdquo; → find \u0026ldquo;OpenSSH Server\u0026rdquo; → Install Configure the service # Run as Administrator # Enable auto-start for sshd Set-Service -Name sshd -StartupType Automatic # Start the service Start-Service sshd # Check status Get-Service sshd # Verify port 22 is listening netstat -ano | findstr :22 Firewall # Check for OpenSSH rule Get-NetFirewallRule -Name *OpenSSH-Server* | Select Name, Enabled # If missing, create it New-NetFirewallRule -Name sshd ` -DisplayName \u0026#39;OpenSSH Server\u0026#39; ` -Enabled True ` -Direction Inbound ` -Protocol TCP ` -LocalPort 22 ` -Action Allow ` -Profile Any Test connection # From the same PC ssh localhost # From another device on the network ssh \u0026lt;your_username\u0026gt;@\u0026lt;Windows_IP\u0026gt; # Example: ssh kirill@192.168.1.100 💡 First connection will ask to confirm the host key fingerprint - type yes.\nKey-based authentication (recommended) On the client (where you connect from) # Generate key pair (if you don\u0026#39;t have one) ssh-keygen -t ed25519 -C \u0026#34;kirill@potatoenergy.ru\u0026#34; # Copy public key to server # For Windows server - manually: type $env:USERPROFILE\\.ssh\\id_ed25519.pub # Copy the output On the server (Windows) # Create .ssh folder in user profile mkdir $env:USERPROFILE\\.ssh -Force # Create/edit authorized_keys notepad $env:USERPROFILE\\.ssh\\authorized_keys # Paste the public key (single line), save # Set correct permissions (REQUIRED) $acl = Get-Acl $env:USERPROFILE\\.ssh\\authorized_keys $acl.SetAccessRuleProtection($true, $false) $rule = New-Object System.Security.AccessControl.FileSystemAccessRule( $env:USERNAME, \u0026#34;Read\u0026#34;, \u0026#34;Allow\u0026#34;) $acl.AddAccessRule($rule) Set-Acl $env:USERPROFILE\\.ssh\\authorized_keys $acl Disable password login (optional, for security) # Edit config notepad C:\\ProgramData\\ssh\\sshd_config # Find and change: # PasswordAuthentication no # PubkeyAuthentication yes # Restart service Restart-Service sshd Config: useful settings File: C:\\ProgramData\\ssh\\sshd_config\n# Allow only specific users AllowUsers kirill admin # Change port (if 22 is busy) Port 2222 # Disable root login PermitRootLogin no # Inactivity timeout ClientAliveInterval 300 ClientAliveCountMax 2 # Logging LogLevel VERBOSE After changes:\nRestart-Service sshd Troubleshooting # Service won\u0026#39;t start → Check logs: Get-WinEvent -LogName \u0026#34;OpenSSH/Operational\u0026#34; -MaxEvents 10 # Port 22 not listening → Check firewall: Get-NetFirewallRule -Name sshd → Check service status: Get-Service sshd # \u0026#34;Permission denied (publickey,password)\u0026#34; → Verify permissions on authorized_keys (owner read-only) → Ensure public key is pasted as one line, no line breaks # Connected but no file access → Check user permissions on Windows folders → Try running terminal as Administrator on the client Links 🌐 Win32-OpenSSH official repo 📘 Microsoft docs 🔑 sshd_config generator ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/windows/openssh/","summary":"\u003cp\u003eOpenSSH is a tool for secure remote access via the SSH protocol. It encrypts all traffic, supports key-based authentication, and works on Windows, Linux, and macOS.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 After setup, you can connect to your Windows PC like a Linux server: \u003ccode\u003essh user@192.168.1.100\u003c/code\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"requirements\"\u003eRequirements\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eOS\u003c/strong\u003e: Windows 10 (1809+), Windows 11, Windows Server 2019/2022\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePrivileges\u003c/strong\u003e: Administrator\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNetwork\u003c/strong\u003e: Access to port 22 (local or remote)\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"installation-3-ways\"\u003eInstallation (3 ways)\u003c/h2\u003e\n\u003ch3 id=\"option-1-powershell-recommended\"\u003eOption 1: PowerShell (recommended)\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Run as Administrator\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Install OpenSSH server\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eAdd-WindowsCapability\u003c/span\u003e \u003cspan class=\"n\"\u003e-Online\u003c/span\u003e \u003cspan class=\"n\"\u003e-Name\u003c/span\u003e \u003cspan class=\"n\"\u003eOpenSSH\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eServer\u003c/span\u003e\u003cspan class=\"p\"\u003e~~~~\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.0\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"py\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"py\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Verify installation\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eGet-WindowsCapability\u003c/span\u003e \u003cspan class=\"n\"\u003e-Online\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e \u003cspan class=\"nb\"\u003eWhere-Object\u003c/span\u003e \u003cspan class=\"n\"\u003eName\u003c/span\u003e \u003cspan class=\"o\"\u003e-like\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;OpenSSH*\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"option-2-dism-alternative\"\u003eOption 2: DISM (alternative)\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003edism\u003c/span\u003e \u003cspan class=\"p\"\u003e/\u003c/span\u003e\u003cspan class=\"n\"\u003eOnline\u003c/span\u003e \u003cspan class=\"p\"\u003e/\u003c/span\u003e\u003cspan class=\"nb\"\u003eAdd-Capability\u003c/span\u003e \u003cspan class=\"p\"\u003e/\u003c/span\u003e\u003cspan class=\"n\"\u003eCapabilityName\u003c/span\u003e\u003cspan class=\"err\"\u003e:\u003c/span\u003e\u003cspan class=\"n\"\u003eOpenSSH\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eServer\u003c/span\u003e\u003cspan class=\"p\"\u003e~~~~\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.0\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"py\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"py\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"option-3-via-settings-gui\"\u003eOption 3: Via Settings (GUI)\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003eSettings → Apps → Optional features\u003c/li\u003e\n\u003cli\u003e\u0026ldquo;Add a feature\u0026rdquo; → find \u0026ldquo;OpenSSH Server\u0026rdquo; → Install\u003c/li\u003e\n\u003c/ol\u003e\n\u003chr\u003e\n\u003ch2 id=\"configure-the-service\"\u003eConfigure the service\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Run as Administrator\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Enable auto-start for sshd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eSet-Service\u003c/span\u003e \u003cspan class=\"n\"\u003e-Name\u003c/span\u003e \u003cspan class=\"n\"\u003esshd\u003c/span\u003e \u003cspan class=\"n\"\u003e-StartupType\u003c/span\u003e \u003cspan class=\"n\"\u003eAutomatic\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Start the service\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eStart-Service\u003c/span\u003e \u003cspan class=\"n\"\u003esshd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Check status\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eGet-Service\u003c/span\u003e \u003cspan class=\"n\"\u003esshd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Verify port 22 is listening\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003enetstat\u003c/span\u003e \u003cspan class=\"n\"\u003e-ano\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003efindstr\u003c/span\u003e \u003cspan class=\"err\"\u003e:\u003c/span\u003e\u003cspan class=\"mf\"\u003e22\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"firewall\"\u003eFirewall\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Check for OpenSSH rule\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eGet-NetFirewallRule\u003c/span\u003e \u003cspan class=\"n\"\u003e-Name\u003c/span\u003e \u003cspan class=\"p\"\u003e*\u003c/span\u003e\u003cspan class=\"nb\"\u003eOpenSSH-Server\u003c/span\u003e\u003cspan class=\"p\"\u003e*\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e \u003cspan class=\"nb\"\u003eSelect \u003c/span\u003e\u003cspan class=\"n\"\u003eName\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eEnabled\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# If missing, create it\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eNew-NetFirewallRule\u003c/span\u003e \u003cspan class=\"n\"\u003e-Name\u003c/span\u003e \u003cspan class=\"n\"\u003esshd\u003c/span\u003e \u003cspan class=\"p\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"n\"\u003e-DisplayName\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;OpenSSH Server\u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"n\"\u003e-Enabled\u003c/span\u003e \u003cspan class=\"n\"\u003eTrue\u003c/span\u003e \u003cspan class=\"p\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"n\"\u003e-Direction\u003c/span\u003e \u003cspan class=\"n\"\u003eInbound\u003c/span\u003e \u003cspan class=\"p\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"n\"\u003e-Protocol\u003c/span\u003e \u003cspan class=\"n\"\u003eTCP\u003c/span\u003e \u003cspan class=\"p\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"n\"\u003e-LocalPort\u003c/span\u003e \u003cspan class=\"mf\"\u003e22\u003c/span\u003e \u003cspan class=\"p\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"n\"\u003e-Action\u003c/span\u003e \u003cspan class=\"n\"\u003eAllow\u003c/span\u003e \u003cspan class=\"p\"\u003e`\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"n\"\u003e-Profile\u003c/span\u003e \u003cspan class=\"n\"\u003eAny\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003ch2 id=\"test-connection\"\u003eTest connection\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-powershell\" data-lang=\"powershell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# From the same PC\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003essh\u003c/span\u003e \u003cspan class=\"n\"\u003elocalhost\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# From another device on the network\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003essh\u003c/span\u003e \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eyour_username\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;@\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWindows_IP\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Example:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003essh\u003c/span\u003e \u003cspan class=\"n\"\u003ekirill\u003c/span\u003e\u003cspan class=\"nv\"\u003e@192\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"py\"\u003e168\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"py\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"py\"\u003e100\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e💡 First connection will ask to confirm the host key fingerprint - type \u003ccode\u003eyes\u003c/code\u003e.\u003c/p\u003e","title":"OpenSSH on Windows: Server Setup"},{"content":"This guide covers advanced OpenWRT configuration for power users. We\u0026rsquo;ll set up DNS-level traffic filtering, secure remote access via WireGuard, metrics monitoring, and automated notifications.\n💡 All sensitive values are replaced with \u0026lt;...\u0026gt;. Substitute your own.\n📦 Package installation opkg update # Monitoring: prometheus exporter + modules opkg install \\ prometheus-node-exporter-lua \\ prometheus-node-exporter-lua-nat_traffic \\ prometheus-node-exporter-lua-netstat \\ prometheus-node-exporter-lua-openwrt \\ prometheus-node-exporter-lua-wifi \\ prometheus-node-exporter-lua-wifi_stations # WireGuard: kernel module + tools + LuCI opkg install \\ kmod-wireguard \\ wireguard-tools \\ luci-proto-wireguard # DNS over HTTPS opkg install https-dns-proxy # Debug utilities opkg install curl jq tmux htop Why these packages:\nprometheus-node-exporter-lua-* - lightweight Lua modules, minimal resource usage kmod-wireguard - kernel-space implementation, faster than userspace https-dns-proxy - encrypts DNS, prevents leaks and censorship 📢 Event notifications On system boot (/etc/rc.local) sleep 10 \u0026amp;\u0026amp; \\ curl -s --max-time 10 -X POST \u0026#34;https://api.telegram.org/bot\u0026lt;TOKEN\u0026gt;/sendMessage\u0026#34; \\ -d chat_id=\u0026lt;CHAT_ID\u0026gt; \\ -d \u0026#34;text=✅ Router: online\u0026#34; \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 \u0026amp;\u0026amp; \\ curl -s --max-time 10 -H \u0026#34;Content-Type: application/json\u0026#34; -X POST \\ -d \u0026#39;{\u0026#34;content\u0026#34;:\u0026#34;✅ Router: online\u0026#34;}\u0026#39; \\ \u0026#34;https://discord.com/api/webhooks/\u0026lt;WEBHOOK_ID\u0026gt;/\u0026lt;WEBHOOK_TOKEN\u0026gt;\u0026#34; \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 \u0026amp;\u0026amp; \\ exit 0 Why this works:\nsleep 10 - lets network initialize before sending --max-time 10 - prevents boot hang if network is down Dual channels (Telegram + Discord) - redundancy for critical alerts Scheduled reboot (Sunday, 03:00) # /etc/crontabs/root 0 3 * * 0 /usr/bin/curl -s --max-time 10 -X POST \u0026#34;https://api.telegram.org/bot\u0026lt;TOKEN\u0026gt;/sendMessage\u0026#34; -d chat_id=\u0026lt;CHAT_ID\u0026gt; -d \u0026#34;text=🔄 Reboot scheduled\u0026#34; \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 \u0026amp;\u0026amp; sleep 10 \u0026amp;\u0026amp; /sbin/reboot Why reboot weekly:\nClears memory leaks in long-running services Night time minimizes user impact Pre-reboot alert distinguishes planned vs. crash reboots 🌐 DNS: smart routing + filtering dnsmasq - local resolver # /etc/config/dhcp config dnsmasq option cachesize \u0026#39;1000\u0026#39; # Cache 1000 entries - memory/speed balance option local \u0026#39;/lan/\u0026#39; # .lan domains stay local option domain \u0026#39;lan\u0026#39; # Default domain for LAN # Route specific domains to specific DNS list server \u0026#39;/api.github.com/8.8.8.8\u0026#39; # GitHub via public DNS list server \u0026#39;/youtube.com/8.8.8.8\u0026#39; # YouTube via public DNS # Block trackers and \u0026#34;smart\u0026#34; features list server \u0026#39;/mask.icloud.com/0.0.0.0\u0026#39; # Block Private Relay list server \u0026#39;/use-application-dns.net/0.0.0.0\u0026#39; # Prevent DNS bypass # Main traffic → local DoH proxy list server \u0026#39;127.0.0.1#5053\u0026#39; list server \u0026#39;127.0.0.1#5054\u0026#39; What makes this special:\nPer-domain upstreams - flexibility and failover 0.0.0.0 blocking - trackers never resolve Local DoH proxy - encryption without ISP dependency https-dns-proxy - DNS over HTTPS # /etc/config/https-dns-proxy config https-dns-proxy option resolver_url \u0026#39;https://\u0026lt;DOH_PROVIDER\u0026gt;/dns-query\u0026#39; option listen_port \u0026#39;5053\u0026#39; option bootstrap_dns \u0026#39;\u0026lt;RESOLVER_IP\u0026gt;\u0026#39; # IP to resolve the DoH endpoint itself config https-dns-proxy option resolver_url \u0026#39;https://\u0026lt;BACKUP_DOH\u0026gt;/dns-query\u0026#39; option listen_port \u0026#39;5054\u0026#39; option bootstrap_dns \u0026#39;\u0026lt;BACKUP_IP\u0026gt;\u0026#39; Why two instances:\nRedundancy: if one provider fails, the other works Different bootstrap_dns - independence from a single resolver Ports 5053/5054 - easy to distinguish in logs and metrics 🔥 Firewall: \u0026ldquo;deny all, allow what\u0026rsquo;s needed\u0026rdquo; Base policy config defaults option input \u0026#39;REJECT\u0026#39; # Block inbound by default option forward \u0026#39;REJECT\u0026#39; # Block forwarding by default option output \u0026#39;ACCEPT\u0026#39; # Outbound allowed option synflood_protect \u0026#39;1\u0026#39; # SYN-flood protection option drop_invalid \u0026#39;1\u0026#39; # Drop malformed packets Why this policy:\nMinimal attack surface: only explicitly allowed traffic passes drop_invalid - protects against scanning and anomalous traffic Zones and rules # LAN - trusted config zone option name \u0026#39;lan\u0026#39; list network \u0026#39;lan\u0026#39; option input \u0026#39;ACCEPT\u0026#39; option forward \u0026#39;ACCEPT\u0026#39; option output \u0026#39;ACCEPT\u0026#39; # WAN - untrusted config zone option name \u0026#39;wan\u0026#39; list network \u0026#39;wan\u0026#39; \u0026#39;wan6\u0026#39; option input \u0026#39;REJECT\u0026#39; option forward \u0026#39;REJECT\u0026#39; option output \u0026#39;ACCEPT\u0026#39; option masq \u0026#39;1\u0026#39; # NAT for outbound # WireGuard - \u0026#34;second LAN\u0026#34; config zone option name \u0026#39;wg\u0026#39; list network \u0026#39;wg0\u0026#39; option input \u0026#39;ACCEPT\u0026#39; option forward \u0026#39;ACCEPT\u0026#39; option output \u0026#39;ACCEPT\u0026#39; option masq \u0026#39;1\u0026#39; Why the wg zone is special:\nWireGuard clients get LAN access like local devices WG→WAN traffic uses the same NAT as LAN→WAN Port forwards (templates) # WireGuard: inbound UDP 51820 → server in LAN config redirect option name \u0026#39;wg\u0026#39; option src \u0026#39;wan\u0026#39; option proto \u0026#39;udp\u0026#39; option src_dport \u0026#39;51820\u0026#39; option dest_ip \u0026#39;\u0026lt;WG_SERVER_LAN_IP\u0026gt;\u0026#39; option dest_port \u0026#39;51820\u0026#39; option target \u0026#39;DNAT\u0026#39; # Game server: arbitrary port → internal host config redirect option name \u0026#39;game-server\u0026#39; option src \u0026#39;wan\u0026#39; option proto \u0026#39;tcp\u0026#39; option src_dport \u0026#39;\u0026lt;EXTERNAL_PORT\u0026gt;\u0026#39; option dest_ip \u0026#39;\u0026lt;INTERNAL_IP\u0026gt;\u0026#39; option dest_port \u0026#39;\u0026lt;INTERNAL_PORT\u0026gt;\u0026#39; option target \u0026#39;DNAT\u0026#39; Notes:\noption proto supports lists: list proto 'tcp' + list proto 'udp' Port ranges: option src_dport '8443-8448' Block QUIC (optional) config rule option name \u0026#39;Block-UDP-80\u0026#39; option proto \u0026#39;udp\u0026#39; option dest_port \u0026#39;80\u0026#39; option target \u0026#39;REJECT\u0026#39; config rule option name \u0026#39;Block-UDP-443\u0026#39; option proto \u0026#39;udp\u0026#39; option dest_port \u0026#39;443\u0026#39; option target \u0026#39;REJECT\u0026#39; Why block QUIC:\nHTTP/3 over QUIC (UDP 443) often bypasses DNS filtering Blocking forces clients to fall back to TCP, where filtering works Most sites support fallback - no visible impact 📡 Network: PPPoE, WireGuard, static leases Interfaces # PPPoE - primary internet (higher priority than default wan) config interface \u0026#39;kmtn\u0026#39; option proto \u0026#39;pppoe\u0026#39; option device \u0026#39;eth0.2\u0026#39; option username \u0026#39;\u0026lt;PPPOE_LOGIN\u0026gt;\u0026#39; option password \u0026#39;\u0026lt;PPPOE_PASSWORD\u0026gt;\u0026#39; option metric \u0026#39;0\u0026#39; # Lower = higher priority # WireGuard - tunnel interface config interface \u0026#39;wg0\u0026#39; option proto \u0026#39;wireguard\u0026#39; option private_key \u0026#39;\u0026lt;WG_PRIVATE_KEY\u0026gt;\u0026#39; option listen_port \u0026#39;51820\u0026#39; list addresses \u0026#39;\u0026lt;WG_SUBNET\u0026gt;/24\u0026#39; config wireguard_wg0 option public_key \u0026#39;\u0026lt;PEER_PUBLIC_KEY\u0026gt;\u0026#39; option preshared_key \u0026#39;\u0026lt;PRESHARED_KEY\u0026gt;\u0026#39; # Extra encryption layer option endpoint_host \u0026#39;\u0026lt;YOUR_DOMAIN_OR_IP\u0026gt;\u0026#39; option endpoint_port \u0026#39;51820\u0026#39; option persistent_keepalive \u0026#39;25\u0026#39; # Keep alive behind NAT option route_allowed_ips \u0026#39;1\u0026#39; # Auto-routing list allowed_ips \u0026#39;\u0026lt;PEER_IP\u0026gt;/32\u0026#39; WireGuard config highlights:\npreshared_key - extra symmetric key, quantum-resistant hedge persistent_keepalive - essential if router is behind provider NAT route_allowed_ips '1' - no manual route management needed Static DHCP leases config host option name \u0026#39;potatoServer\u0026#39; option mac \u0026#39;\u0026lt;MAC_ADDRESS\u0026gt;\u0026#39; option ip \u0026#39;192.168.1.\u0026lt;STATIC_IP\u0026gt;\u0026#39; option leasetime \u0026#39;infinite\u0026#39; Why static leases:\nServers and critical devices always have the same IP Simplifies firewall rules and monitoring leasetime 'infinite' - lease never expires, even if device is offline 📊 Monitoring: prometheus-node-exporter Configuration # /etc/config/prometheus-node-exporter-lua config prometheus-node-exporter-lua \u0026#39;main\u0026#39; option listen_interface \u0026#39;lan\u0026#39; # Listen on LAN only - security option listen_port \u0026#39;9101\u0026#39; Access metrics http://192.168.1.1:9101/metrics What each module collects Module Metrics Why it matters nat_traffic NAT sessions, bytes in/out Understand NAT load netstat Active connections, states Detect anomalies and leaks openwrt Version, uptime, packages Inventory and alerting wifi Signal, channel, airtime load Optimize wireless wifi_stations Per-client RSSI, speed, info Diagnose problematic devices Grafana PromQL examples # CPU usage % 100 - (avg by (instance) (irate(node_cpu_seconds_total{mode=\u0026#34;idle\u0026#34;}[5m])) * 100) # WAN traffic (bits/sec) irate(node_network_receive_bytes_total{device=\u0026#34;eth0.2\u0026#34;}[5m]) * 8 # WiFi client count count(node_wifi_station_info) # Active NAT sessions node_nat_traffic_sessions Why prometheus-node-exporter-lua:\nWritten in Lua - minimal resource footprint Integrates with OpenWRT\u0026rsquo;s metric ecosystem No separate binary or Python dependency 📶 WiFi: two networks for different needs # 5 GHz - speed config wifi-iface \u0026#39;default_radio0\u0026#39; option device \u0026#39;radio0\u0026#39; option network \u0026#39;lan\u0026#39; option mode \u0026#39;ap\u0026#39; option ssid \u0026#39;\u0026lt;SSID_5GHZ\u0026gt;\u0026#39; option encryption \u0026#39;psk2\u0026#39; option key \u0026#39;\u0026lt;WIFI_PASSWORD\u0026gt;\u0026#39; option band \u0026#39;5g\u0026#39; option htmode \u0026#39;VHT80\u0026#39; # 2.4 GHz - range and compatibility config wifi-iface \u0026#39;default_radio1\u0026#39; option device \u0026#39;radio1\u0026#39; option network \u0026#39;lan\u0026#39; option mode \u0026#39;ap\u0026#39; option ssid \u0026#39;\u0026lt;SSID_2GHZ\u0026gt;\u0026#39; option encryption \u0026#39;psk2\u0026#39; option key \u0026#39;\u0026lt;WIFI_PASSWORD\u0026gt;\u0026#39; option band \u0026#39;2g\u0026#39; option htmode \u0026#39;HT40\u0026#39; Why separate SSIDs:\nIoT devices often don\u0026rsquo;t support 5 GHz - connect to 2.4 Manual control: speed where needed (5 GHz), range where needed (2.4) Different htmode: VHT80 for 5 GHz (wide channel), HT40 for 2.4 (stability) 🔧 Admin commands cheat sheet # WireGuard status (peers, traffic, last handshake) wg show # Restart services /etc/init.d/network restart /etc/init.d/firewall restart /etc/init.d/https-dns-proxy restart # Logs: errors and warnings logread | grep -iE \u0026#39;error|warn|fail\u0026#39; # Recent kernel messages dmesg | tail -50 # Check listening ports netstat -tulpn # Test DNS via specific port nslookup google.com 127.0.0.1#5053 # Live firewall rule inspection iptables -L -n -v | grep -E \u0026#39;REJECT|ACCEPT\u0026#39; ⚠️ Troubleshooting # No web UI access → Check firewall rule for port 80/443 in \u0026#39;lan\u0026#39; zone → Try SSH: ssh root@192.168.1.1 # WireGuard won\u0026#39;t start → Verify keys: no spaces, no line breaks, single line → Ensure port 51820 is free: netstat -ulpn | grep 51820 → Check route: `ip route | grep wg0` # DNS not resolving → Proxy status: `/etc/init.d/https-dns-proxy status` → Bootstrap must be IP, not domain: `option bootstrap_dns \u0026#39;8.8.8.8\u0026#39;` → Test: `nslookup google.com 127.0.0.1#5053` # Metrics not collected → Is port 9101 listening: `netstat -tulpn | grep 9101` → Does interface \u0026#39;lan\u0026#39; exist: `ifconfig | grep br-lan` → Check firewall: is inbound on 9101 allowed from \u0026#39;lan\u0026#39; Links 🌐 OpenWRT Documentation 🔐 WireGuard Quick Start 🛡 DNS-over-HTTPS Providers 📊 prometheus-node-exporter-lua 🧰 OpenWRT Package Search ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/openwrt/setup/","summary":"\u003cp\u003eThis guide covers advanced OpenWRT configuration for power users. We\u0026rsquo;ll set up DNS-level traffic filtering, secure remote access via WireGuard, metrics monitoring, and automated notifications.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 All sensitive values are replaced with \u003ccode\u003e\u0026lt;...\u0026gt;\u003c/code\u003e. Substitute your own.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"-package-installation\"\u003e📦 Package installation\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eopkg update\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Monitoring: prometheus exporter + modules\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eopkg install \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  prometheus-node-exporter-lua \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  prometheus-node-exporter-lua-nat_traffic \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  prometheus-node-exporter-lua-netstat \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  prometheus-node-exporter-lua-openwrt \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  prometheus-node-exporter-lua-wifi \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  prometheus-node-exporter-lua-wifi_stations\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# WireGuard: kernel module + tools + LuCI\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eopkg install \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  kmod-wireguard \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  wireguard-tools \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  luci-proto-wireguard\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# DNS over HTTPS\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eopkg install https-dns-proxy\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Debug utilities\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eopkg install curl jq tmux htop\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eWhy these packages\u003c/strong\u003e:\u003c/p\u003e","title":"OpenWRT: Advanced Router Configuration"},{"content":"OrangePI and other ARM single-board computers often use eMMC or SD cards with limited write endurance. Over time, storage fills up, degrades, or fails. This guide describes a method for data recovery and migration to external storage (USB SSD/HDD) via a chroot environment.\n💡 Method is universal: works for OrangePI, Raspberry Pi, NanoPi, and other ARM systems.\n📦 Preparation Requirements Component Requirements USB drive SSD/HDD, capacity ≥ eMMC data Live image Any Linux with ARM support (optional) Access root or sudo, physical access to board Network Ethernet or WiFi (for remote access) Check connected storage # Show all MMC devices (eMMC, SD card) ls /dev/mmc* # Show all block devices lsblk # Show partitions and mount points df -h Expected output:\n/dev/mmcblk0 - built-in eMMC or SD card /dev/sda, /dev/sdb - connected USB drives 🔧 Mounting partitions Step 1: Mount eMMC root filesystem # Create mount point mkdir -p /mnt # Mount root partition (usually mmcblk0p1 or p2) mount /dev/mmcblk0p2 /mnt Why:\nDirect access to filesystem for diagnostics Ability to boot from USB but work with eMMC data Step 2: Connect external storage # Create USB mount point mkdir -p /mnt/usb # Mount USB partition mount /dev/sda1 /mnt/usb Why USB:\neMMC has limited write cycles (~10K cycles) USB SSD is more reliable for long-term storage Easier to replace when degraded Step 3: Verify accessibility # Confirm partitions are mounted df -h /mnt df -h /mnt/usb # Check access permissions ls -la /mnt/ ls -la /mnt/usb/ 🚀 Working via chroot Enter chroot environment # Change root to mounted system chroot /mnt /bin/bash What chroot provides:\nWork inside original system, not live image Access to installed packages, configs, services Run commands as the target system Verify inside chroot # Confirm we\u0026#39;re in the right system hostname cat /etc/os-release # Check mounts inside chroot df -h ⚠️ If /proc, /sys, /dev needed - mount before chroot:\nmount -t proc proc /mnt/proc mount -t sysfs sys /mnt/sys mount --bind /dev /mnt/dev 📊 Analyze disk usage Check usage by directory # Home directory size du -h /home # Project/application size du -h /opt/project # Overall partition stats df -h / Why du -h:\n-h - human-readable format (K, M, G) Shows actual disk usage, not file sizes Helps find \u0026ldquo;space hogs\u0026rdquo; Find large files # Find files \u0026gt; 100MB find / -type f -size +100M -exec ls -lh {} \\; # Top 10 largest directories du -h / | sort -rh | head -10 📋 Data migration via rsync Basic sync # Copy home directory and projects to USB rsync -av /home /opt/project /mnt/usb/ rsync options:\n-a - archive mode (preserves permissions, links, timestamps) -v - verbose (shows copy progress) Advanced sync # With progress and deletion of extra files on target rsync -av --progress --delete /home /opt/project /mnt/usb/ # With compression for slow connections rsync -avz --progress /home /opt/project /mnt/usb/ Why rsync, not cp:\nCopies only changed files on re-run Preserves all metadata (owner, permissions, timestamps) Shows progress and speed Can be interrupted and resumed Verify after copy # Compare source and destination sizes du -sh /home /opt/project du -sh /mnt/usb/home /mnt/usb/project # Check checksums (optional) md5sum /home/user/.bashrc md5sum /mnt/usb/home/user/.bashrc 🔄 Boot from USB (optional) Change boot configuration # For OrangePI with U-Boot # Edit /boot/boot.cmd or /boot/uEnv.txt # Specify USB as root partition # Example for uEnv.txt: setenv bootargs \u0026#39;console=ttyS0,115200 root=/dev/sda1 rootwait\u0026#39; Or via fstab # Mount USB as root on boot # /etc/fstab /dev/sda1 / ext4 defaults,noatime 0 1 Why boot from USB:\nOffload eMMC from writes (system logs, cache) Extend built-in storage lifespan Easy replacement/upgrade without reflashing 🛡 Recovery after failure If system won\u0026rsquo;t boot # Boot from live image (SD card or network) # Mount eMMC and USB as described above # Use rsync to recover data If eMMC fully degraded # Move entire system to USB rsync -avx / /mnt/usb/ # Reinstall bootloader on USB # For U-Boot: dd if=/usr/lib/u-boot/orangepi_pc_plus/u-boot-sunxi-with-spl.bin of=/dev/sda bs=1024 seek=8 ⚠️ Bootloader operations require exact board model matching!\n🔧 Diagnostic commands # Check eMMC health (if supported) smartctl -a /dev/mmcblk0 # Check write errors in logs dmesg | grep -iE \u0026#39;error|fail|mmc\u0026#39; # Get USB drive model and speed lsusb -t hdparm -I /dev/sda # Test read/write speed dd if=/dev/zero of=/mnt/usb/test bs=1M count=1024 conv=fdatasync dd if=/mnt/usb/test of=/dev/null bs=1M ⚠️ Common issues # USB not detected → Check power: some SSDs need external power supply → Try different USB 3.0 port → Check dmesg | tail after connection # Mount error → Check filesystem: fsck /dev/sda1 → Ensure partition not busy: umount /dev/sda1 # rsync interrupted → Use --partial for resume: rsync -av --partial /source /dest → Check power stability # chroot not working → Mount pseudo-FS before chroot: mount -t proc proc /mnt/proc mount --bind /dev /mnt/dev → Check architecture: uname -m Links 🌐 OrangePI Official Wiki 📦 Armbian Documentation 🔧 rsync Man Page 💾 eMMC vs SSD Lifespan ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/linux/orangepi/storage-recovery/","summary":"\u003cp\u003eOrangePI and other ARM single-board computers often use eMMC or SD cards with limited write endurance. Over time, storage fills up, degrades, or fails. This guide describes a method for data recovery and migration to external storage (USB SSD/HDD) via a chroot environment.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Method is universal: works for OrangePI, Raspberry Pi, NanoPi, and other ARM systems.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"-preparation\"\u003e📦 Preparation\u003c/h2\u003e\n\u003ch3 id=\"requirements\"\u003eRequirements\u003c/h3\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eComponent\u003c/th\u003e\n          \u003cth\u003eRequirements\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eUSB drive\u003c/td\u003e\n          \u003ctd\u003eSSD/HDD, capacity ≥ eMMC data\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eLive image\u003c/td\u003e\n          \u003ctd\u003eAny Linux with ARM support (optional)\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eAccess\u003c/td\u003e\n          \u003ctd\u003eroot or sudo, physical access to board\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eNetwork\u003c/td\u003e\n          \u003ctd\u003eEthernet or WiFi (for remote access)\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"check-connected-storage\"\u003eCheck connected storage\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Show all MMC devices (eMMC, SD card)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003els /dev/mmc*\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Show all block devices\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003elsblk\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Show partitions and mount points\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edf -h\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eExpected output\u003c/strong\u003e:\u003c/p\u003e","title":"OrangePI: Data Recovery \u0026 Migration"},{"content":"WSL (Windows Subsystem for Linux) lets you run native Linux command-line tools directly on Windows - no VM, no dual boot.\nWSL1 - syscall translation layer (fast, but not 100% compatible)\nWSL2 - real Linux kernel in lightweight virtualization (full compatibility, slightly more resources)\n💡 Use WSL2. Near-native performance with full Docker, systemd, and Linux feature support.\nRequirements OS: Windows 10 (2004+, build 19041+) or Windows 11 Architecture: x64 or ARM64 Privileges: Administrator (for install) Virtualization: Enabled in BIOS/UEFI (Hyper-V Platform) Check virtualization:\nsysteminfo | findstr /I \u0026#34;Virtualization\u0026#34; # Should show: \u0026#34;Hyper-V detected\u0026#34; or \u0026#34;Virtualization Enabled\u0026#34; Install (one command) # Run PowerShell as Administrator wsl --install This does everything:\n✅ Enables WSL and VirtualMachinePlatform features ✅ Downloads and installs Ubuntu (default distro) ✅ Sets WSL2 as default version Reboot your PC after completion.\nManual install (if --install fails) # 1. Enable features dism /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart # 2. Reboot shutdown /r /t 0 # 3. Download and install WSL2 kernel # https://aka.ms/wsl2kernel # 4. Set WSL2 as default wsl --set-default-version 2 # 5. Install distro from Microsoft Store # Or via winget: winget install Ubuntu.Ubuntu.24.04 First run # After reboot, a terminal opens with Linux setup # Create username and password (typing is hidden - normal) # Update packages (Ubuntu/Debian) sudo apt update \u0026amp;\u0026amp; sudo apt upgrade -y # Install basic tools sudo apt install -y git curl wget build-essential Manage distributions # List installed distros wsl --list --verbose # Short form: wsl -l -v # Launch specific distro wsl -d Ubuntu-24.04 wsl -d Debian # Stop (terminate) a distro wsl --terminate Ubuntu-24.04 # Stop all wsl --shutdown # Set version (1 or 2) wsl --set-version Ubuntu-24.04 2 # Set default distro wsl --set-default Ubuntu-24.04 # Export / import wsl --export Ubuntu-24.04 D:\\backups\\ubuntu.tar wsl --import MyUbuntu D:\\wsl\\MyUbuntu D:\\backups\\ubuntu.tar --version 2 # Unregister (delete) distro - all data lost! wsl --unregister Ubuntu-24.04 File system access From Linux → Windows # Windows drives mounted under /mnt/ ls /mnt/c/Users/ponfertato/Documents # Open Explorer in current directory explorer.exe . From Windows → Linux # Open user\u0026#39;s home in Explorer \\\\wsl$\\Ubuntu-24.04\\home\\kirill # Or from terminal: explorer.exe \\\\wsl$\\Ubuntu-24.04\\home\\kirill ⚠️ Don\u0026rsquo;t edit Linux files from Windows apps directly (via \\\\wsl$). This can corrupt metadata. Use Linux tools inside WSL.\nNetwork and ports # Get your WSL IP ip addr show eth0 | grep inet # Windows and WSL share localhost (ports forward automatically) # Start a web server in WSL: python3 -m http.server 8000 # Accessible from Windows at: # http://localhost:8000 If ports don\u0026rsquo;t forward:\n# Check settings wsl --status # Enable auto-forwarding (if disabled) # In %USERPROFILE%\\.wslconfig: [wsl2] networkingMode=mirrored localhostForwarding=true Terminal and editor integration Use Windows Terminal # Install from Microsoft Store or: winget install Microsoft.WindowsTerminal # WSL profiles added automatically # Switch shells: Ctrl+Shift+1/2/3... VS Code + WSL # Inside WSL: code . # Opens VS Code on Windows connected to WSL environment # Install \u0026#34;Remote - WSL\u0026#34; extension if prompted Run Windows apps from WSL # Launch Notepad from Linux: notepad.exe /mnt/c/Users/ponfertato/notes.txt # Launch PowerShell: powershell.exe Get-Process Docker in WSL2 # Install Docker Desktop for Windows winget install Docker.DockerDesktop # In Docker Desktop settings: # Settings → Resources → WSL Integration → enable your distro # Test in WSL: docker run hello-world 💡 Docker runs natively in WSL2 - no extra setup needed inside Linux.\nsystemd in WSL (for services) # Enable systemd (WSL 0.67.6+) # Create/edit: /etc/wsl.conf [boot] systemd=true # Apply: # From PowerShell: wsl --terminate Ubuntu-24.04 wsl -d Ubuntu-24.04 # Verify: systemctl status Now services work: systemctl start nginx, enable docker, etc.\nUseful settings (.wslconfig) File: %USERPROFILE%\\.wslconfig (create if missing)\n[wsl2] # Memory: 4 GB (or 50% of RAM) memory=4GB # CPUs: 4 cores processors=4 # Swap: 2 GB swap=2GB # Disk: dynamic, up to 256 GB diskSize=256GB # Network: mirrored mode (best compatibility) networkingMode=mirrored # Auto-shutdown: enable autoShutdown=true # Idle timeout: 10 minutes idleTimeout=600000 Apply: wsl --shutdown, then restart distro.\nTroubleshooting # WSL won\u0026#39;t start, error 0x80370102 → Enable virtualization in BIOS → Check: \u0026#34;Control Panel\u0026#34; → \u0026#34;Programs\u0026#34; → \u0026#34;Turn Windows features on/off\u0026#34; → Hyper-V Platform # \u0026#34;The virtual machine could not be started\u0026#34; → Run as admin: bcdedit /set hypervisorlaunchtype auto → Reboot # Slow file access in /mnt/c → Store projects inside Linux FS: ~/projects, not /mnt/c/... → Use VS Code Remote WSL for editing # sudo fails / password rejected → Reset password: # In PowerShell: wsl -d Ubuntu-24.04 -u root # Inside WSL: passwd kirill # Port conflicts with Windows → Check reserved ports: netsh interface ipv4 show excludedportrange protocol=tcp → Or change port in your app Backup and migration # Export distro wsl --export Ubuntu-24.04 D:\\wsl-backups\\ubuntu-$(Get-Date -Format \u0026#39;yyyy-MM-dd\u0026#39;).tar # Import on another PC wsl --import Ubuntu-24.04 D:\\WSL\\Ubuntu D:\\wsl-backups\\ubuntu-2026-03-16.tar --version 2 # Set default user after import # Create: /etc/wsl.conf in imported distro [user] default=kirill Links 🌐 Official WSL docs 📦 Distros in Microsoft Store ⚙️ .wslconfig settings 🐳 Docker + WSL2 ","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/blog/windows/wsl/","summary":"\u003cp\u003eWSL (Windows Subsystem for Linux) lets you run native Linux command-line tools directly on Windows - no VM, no dual boot.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWSL1\u003c/strong\u003e - syscall translation layer (fast, but not 100% compatible)\u003cbr\u003e\n\u003cstrong\u003eWSL2\u003c/strong\u003e - real Linux kernel in lightweight virtualization (full compatibility, slightly more resources)\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Use WSL2. Near-native performance with full Docker, systemd, and Linux feature support.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"requirements\"\u003eRequirements\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eOS\u003c/strong\u003e: Windows 10 (2004+, build 19041+) or Windows 11\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eArchitecture\u003c/strong\u003e: x64 or ARM64\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePrivileges\u003c/strong\u003e: Administrator (for install)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eVirtualization\u003c/strong\u003e: Enabled in BIOS/UEFI (Hyper-V Platform)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eCheck virtualization:\u003c/strong\u003e\u003c/p\u003e","title":"WSL2: Developer's Complete Guide"},{"content":"We are excited to announce that a new member has joined our team - iluvcocacola! 🎉\niluvcocacola brings fresh ideas and unique experience that will help us reach new heights in our project. We are confident that her skills and enthusiasm will be a valuable addition to our team.\nWhy is this important? Adding a new person to the team always brings new perspectives and opportunities for growth. We believe that iluvcocacola will help us improve our processes and achieve our goals.\nPlease join us in welcoming iluvcocacola and support her in this new endeavor. We look forward to working together and achieving success!\nExpectations Collaboration: We hope for active participation from iluvcocacola in team discussions and projects. Ideas: We encourage new ideas and approaches that can enhance our work. Support: The team is always ready to support iluvcocacola during the adaptation and learning process. Welcome to the team, iluvcocacola! We are glad to have you with us!\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/news/team/iluvcocacola/","summary":"\u003cp\u003eWe are excited to announce that a new member has joined our team - \u003cstrong\u003eiluvcocacola\u003c/strong\u003e! 🎉\u003c/p\u003e\n\u003cp\u003eiluvcocacola brings fresh ideas and unique experience that will help us reach new heights in our project. We are confident that her skills and enthusiasm will be a valuable addition to our team.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003e\u003cstrong\u003eWhy is this important?\u003c/strong\u003e\u003c/em\u003e \u003cbr\u003e\nAdding a new person to the team always brings new perspectives and opportunities for growth. We believe that iluvcocacola will help us improve our processes and achieve our goals.\u003c/p\u003e","title":"Welcome iluvcocacola to the Team!"},{"content":"ArchiSteamFarm: Steam Manager 🎮 Autopilot for your Steam accounts under our management.\nWhat does:\n⚙️ Automatic activation of game distributions 🃏 Autofarming of cards and badges 👥 Manage multiple accounts from one interface 📊 Logging of actions and event notifications 🔐 Session isolation and lock protection How to use:\nRequest access from the administrator Provide the minimum data: login + sharedSecret (optional) The bot works in the background - you receive cards, we monitor the stability Security:\nData is encrypted at the configuration level The bot\u0026rsquo;s access is limited to farming only You still have full account control. Access: on request • Contact\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/archisteamfarm/","summary":"\u003ch3 id=\"archisteamfarm-steam-manager-\"\u003eArchiSteamFarm: Steam Manager \u003ca href=\"https://github.com/JustArchiNET/ArchiSteamFarm\"\u003e🎮\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eAutopilot\u003c/strong\u003e for your Steam accounts under our management.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat does:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e⚙️ Automatic activation of game distributions\u003c/li\u003e\n\u003cli\u003e🃏 Autofarming of cards and badges\u003c/li\u003e\n\u003cli\u003e👥 Manage multiple accounts from one interface\u003c/li\u003e\n\u003cli\u003e📊 Logging of actions and event notifications\u003c/li\u003e\n\u003cli\u003e🔐 Session isolation and lock protection\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to use:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eRequest access from the administrator\u003c/li\u003e\n\u003cli\u003eProvide the minimum data: login + sharedSecret (optional)\u003c/li\u003e\n\u003cli\u003eThe bot works in the background - you receive cards, we monitor the stability\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eSecurity:\u003c/strong\u003e\u003c/p\u003e","title":"ArchiSteamFarm: Steam Manager"},{"content":"Authelia: Access protection 🔒 Single sign-on to all Potato Energy services with enterprise-level protection.\nWhat does:\n🔐 A single account for all services - no need to remember passwords anymore 📱 Two-factor authentication (TOTP, WebAuthn, push notifications) 🎯 Flexible access policies: by user, IP, device 🛡️ Protection against brute force and suspicious inputs 📋 Detailed logs of authorizations for administrators How to use:\nWhen logging into any service for the first time, create an Authelia account Set up 2FA in your personal account (recommended) Log in to the services with one click - general authorization For administrators: Rights management, forced 2FA, session auditing - all in a single dashboard.\nAccess: automatically upon registration\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/authelia/","summary":"\u003ch3 id=\"authelia-access-protection-\"\u003eAuthelia: Access protection \u003ca href=\"https://www.authelia.com/\"\u003e🔒\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eSingle sign-on\u003c/strong\u003e to all Potato Energy services with enterprise-level protection.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat does:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e🔐 A single account for all services - no need to remember passwords anymore\u003c/li\u003e\n\u003cli\u003e📱 Two-factor authentication (TOTP, WebAuthn, push notifications)\u003c/li\u003e\n\u003cli\u003e🎯 Flexible access policies: by user, IP, device\u003c/li\u003e\n\u003cli\u003e🛡️ Protection against brute force and suspicious inputs\u003c/li\u003e\n\u003cli\u003e📋 Detailed logs of authorizations for administrators\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to use:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eWhen logging into any service for the first time, create an Authelia account\u003c/li\u003e\n\u003cli\u003eSet up 2FA in your personal account (recommended)\u003c/li\u003e\n\u003cli\u003eLog in to the services with one click - general authorization\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eFor administrators:\u003c/strong\u003e\nRights management, forced 2FA, session auditing - all in a single dashboard.\u003c/p\u003e","title":"Authelia: Protection of Digital Space"},{"content":"Diun: Guardian of the relevance of containers 🔄 Personal assistant for updating Docker images.\nWhat does:\n🔍 Monitors image tags in Docker Hub, GitHub, and private registries 📩 Sends notifications to Telegram, Discord when new versions are released 📋 Detailed log of changes with links to releases How to use:\nDiun works in the background - no configuration required You will receive a notification when an update is available for the service. The administrator applies the update or sets up an auto-update For administrators: Flexible rules, filtering, and notifications are all in the config.\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/diun/","summary":"\u003ch3 id=\"diun-guardian-of-the-relevance-of-containers-\"\u003eDiun: Guardian of the relevance of containers \u003ca href=\"https://github.com/crazy-max/diun\"\u003e🔄\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003ePersonal assistant\u003c/strong\u003e for updating Docker images.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat does:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e🔍 Monitors image tags in Docker Hub, GitHub, and private registries\u003c/li\u003e\n\u003cli\u003e📩 Sends notifications to Telegram, Discord when new versions are released\u003c/li\u003e\n\u003cli\u003e📋 Detailed log of changes with links to releases\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to use:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eDiun works in the background - no configuration required\u003c/li\u003e\n\u003cli\u003eYou will receive a notification when an update is available for the service.\u003c/li\u003e\n\u003cli\u003eThe administrator applies the update or sets up an auto-update\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eFor administrators:\u003c/strong\u003e\nFlexible rules, filtering, and notifications are all in the config.\u003c/p\u003e","title":"Diun: Container Relevance Guardian"},{"content":"Drawpile: Collaborative Creativity 🎨 Cooperative server for real-time drawing.\nWhat does:\n✏️ Drawing together on the same canvas: up to 8+ users 🖌️ Full-fledged tools: layers, brushes, selection, transformation 💬 Built-in chat for coordination in the process 🎥 Recording sessions with the possibility of playback 📤 Exporting the result to PNG/PSD How to connect:\nDownload the client from drawpile.net or launch online version in your browser Run → \u0026ldquo;Connect\u0026rdquo; → enter the address: connect.potatoenergy.ru:27750 Choose a nickname, join the session, or create your own Rules: Respect the creativity of others, do not spam in the chat, coordinate actions. The details can be found in the session description.\nStatus: https://status.potatoenergy.ru/history/drawpile\nAccess: connect.potatoenergy.ru:27750 • public, no registration required\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/drawpile/","summary":"\u003ch3 id=\"drawpile-collaborative-creativity-\"\u003eDrawpile: Collaborative Creativity \u003ca href=\"https://drawpile.net/\"\u003e🎨\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eCooperative server\u003c/strong\u003e for real-time drawing.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat does:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e✏️ Drawing together on the same canvas: up to 8+ users\u003c/li\u003e\n\u003cli\u003e🖌️ Full-fledged tools: layers, brushes, selection, transformation\u003c/li\u003e\n\u003cli\u003e💬 Built-in chat for coordination in the process\u003c/li\u003e\n\u003cli\u003e🎥 Recording sessions with the possibility of playback\u003c/li\u003e\n\u003cli\u003e📤 Exporting the result to PNG/PSD\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to connect:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eDownload the client from \u003ca href=\"https://drawpile.net/download\"\u003edrawpile.net\u003c/a\u003e or launch \u003ca href=\"https://web.drawpile.net/\"\u003eonline version\u003c/a\u003e in your browser\u003c/li\u003e\n\u003cli\u003eRun → \u0026ldquo;Connect\u0026rdquo; → enter the address: \u003ccode\u003econnect.potatoenergy.ru:27750\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eChoose a nickname, join the session, or create your own\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eRules:\u003c/strong\u003e\nRespect the creativity of others, do not spam in the chat, coordinate actions. The details can be found in the session description.\u003c/p\u003e","title":"Drawpile: Collaborative Creativity"},{"content":"Error-Pages: Custom error pages 🚨 Friendly messages instead of the standard \u0026ldquo;404 Not Found\u0026rdquo;.\nWhat does:\n🎨 Stylish pages for 4xx/5xx errors in a single Potato Energy brand 🌍 Automatic language detection and dark/light theme 🔧 Useful tips: \u0026ldquo;check the URL\u0026rdquo;, \u0026ldquo;go back to the main page\u0026rdquo;, \u0026ldquo;write to support\u0026rdquo; 📊 Error logging for administrators ⚡ Lightweight static pages - load even in case of backend failures How it works:\nIf there is an access error, Nginx/Traefik redirects to a custom page. You see a clear message with options for action. The administrator receives notification of critical failures For administrators: Flexible customization of texts, redirects, and styles through a single configuration.\nAccess: automatically • triggered in case of errors\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/error-pages/","summary":"\u003ch3 id=\"error-pages-custom-error-pages-\"\u003eError-Pages: Custom error pages \u003ca href=\"https://github.com/tarampampam/error-pages\"\u003e🚨\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eFriendly messages\u003c/strong\u003e instead of the standard \u0026ldquo;404 Not Found\u0026rdquo;.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat does:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e🎨 Stylish pages for 4xx/5xx errors in a single Potato Energy brand\u003c/li\u003e\n\u003cli\u003e🌍 Automatic language detection and dark/light theme\u003c/li\u003e\n\u003cli\u003e🔧 Useful tips: \u0026ldquo;check the URL\u0026rdquo;, \u0026ldquo;go back to the main page\u0026rdquo;, \u0026ldquo;write to support\u0026rdquo;\u003c/li\u003e\n\u003cli\u003e📊 Error logging for administrators\u003c/li\u003e\n\u003cli\u003e⚡ Lightweight static pages - load even in case of backend failures\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow it works:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eIf there is an access error, Nginx/Traefik redirects to a custom page.\u003c/li\u003e\n\u003cli\u003eYou see a clear message with options for action.\u003c/li\u003e\n\u003cli\u003eThe administrator receives notification of critical failures\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eFor administrators:\u003c/strong\u003e\nFlexible customization of texts, redirects, and styles through a single configuration.\u003c/p\u003e","title":"Error-Pages: Custom Error Pages"},{"content":"Grafana: Visibility of each bit 📈 Real-time monitoring of all Potato Energy services.\nWhat shows:\nDashboards on CPU, RAM, disks, network for each service\n🖥️ Dashboards on CPU, RAM, disks, network for each service 🔄 Container status, uptime, logs in one interface 🚨 Visualization of alerts: you see the problem before it becomes critical 📊 Flexible schedules: from simple metrics to complex queries to Prometheus 📤 Export reports to PNG/PDF for presentation or audit How to use:\nOpen the grafana.potatoenergy.ru View public dashboards without authorization or log in with your Potato Energy account (via Authelia) Log in to create your own charts and access additional dashboards. For the dev group: Editing dashboards, managing data sources, and configuring notifications.\nStatus: https://status.potatoenergy.ru/history/grafana\nAccess: grafana.potatoenergy.ru • viewing is open, editing is allowed\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/grafana/","summary":"\u003ch3 id=\"grafana-visibility-of-each-bit-\"\u003eGrafana: Visibility of each bit \u003ca href=\"https://grafana.com/\"\u003e📈\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eReal-time monitoring\u003c/strong\u003e of all Potato Energy services.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat shows:\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eDashboards on CPU, RAM, disks, network for each service\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e🖥️ Dashboards on CPU, RAM, disks, network for each service\u003c/li\u003e\n\u003cli\u003e🔄 Container status, uptime, logs in one interface\u003c/li\u003e\n\u003cli\u003e🚨 Visualization of alerts: you see the problem before it becomes critical\u003c/li\u003e\n\u003cli\u003e📊 Flexible schedules: from simple metrics to complex queries to Prometheus\u003c/li\u003e\n\u003cli\u003e📤 Export reports to PNG/PDF for presentation or audit\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to use:\u003c/strong\u003e\u003c/p\u003e","title":"Grafana: Visibility of Every Bit"},{"content":"Home Assistant: Smart Home 🏠 Control Center for your smart devices under your control.\nWhat does:\n💡 Control of lights, devices, sockets from one interface 🤖 Automation: \u0026ldquo;if it\u0026rsquo;s dark → turn on the light\u0026rdquo;, \u0026ldquo;if you\u0026rsquo;re gone → turn everything off\u0026rdquo; 🔐 Local operation - without clouds and dependence on the Internet 📊 Energy module: consumption tracking and cost optimization 🌐 Supports 1000+ devices: Zigbee, Z-Wave, Wi-Fi, Matter How to use:\nOpen the home.potatoenergy.ru (access is only for the hass group) Select the device or script in the dashboard Create your own automation through a visual editor For the hass group: Full access to configuration, integrations, logs, and backups.\nAccess: home.potatoenergy.ru • according to Potato Energy credentials (only according to the rights of the hass group)\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/home-assistant/","summary":"\u003ch3 id=\"home-assistant-smart-home-\"\u003eHome Assistant: Smart Home \u003ca href=\"https://www.home-assistant.io/\"\u003e🏠\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eControl Center\u003c/strong\u003e for your smart devices under your control.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat does:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e💡 Control of lights, devices, sockets from one interface\u003c/li\u003e\n\u003cli\u003e🤖 Automation: \u0026ldquo;if it\u0026rsquo;s dark → turn on the light\u0026rdquo;, \u0026ldquo;if you\u0026rsquo;re gone → turn everything off\u0026rdquo;\u003c/li\u003e\n\u003cli\u003e🔐 Local operation - without clouds and dependence on the Internet\u003c/li\u003e\n\u003cli\u003e📊 Energy module: consumption tracking and cost optimization\u003c/li\u003e\n\u003cli\u003e🌐 Supports 1000+ devices: Zigbee, Z-Wave, Wi-Fi, Matter\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to use:\u003c/strong\u003e\u003c/p\u003e","title":"Home Assistant: Intelligent Core of Your Home"},{"content":"Mastodon: Your federated space 🌐 An uncensored social network where you own your data.\nWhat does:\n📝 Publishing posts, threads, images, and videos without an algorithmic feed 🌍 Federation via ActivityPub: communication with Mastodon, Pixelfed, and PeerTube users 🔒 Flexible privacy: subscriber-only posts, local messages, CW tags 🎨 Custom emojis, design themes, and content moderation 🛡️ Local moderation and spam blocking - you control your space How to join:\nGo to social.potatoenergy.ru Log in with your Potato Energy account (via Authelia) Set up a profile and start publishing - you are already in the federation For moderators: Tools for reporting, silencing/blocking, and federal rules are all in the admin panel.\nStatus: https://status.potatoenergy.ru/history/mastodon\nAccess: social.potatoenergy.ru • according to Potato Energy credentials\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/mastodon/","summary":"\u003ch3 id=\"mastodon-your-federated-space-\"\u003eMastodon: Your federated space \u003ca href=\"https://joinmastodon.org/\"\u003e🌐\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eAn uncensored social network\u003c/strong\u003e where you own your data.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat does:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e📝 Publishing posts, threads, images, and videos without an algorithmic feed\u003c/li\u003e\n\u003cli\u003e🌍 Federation via ActivityPub: communication with Mastodon, Pixelfed, and PeerTube users\u003c/li\u003e\n\u003cli\u003e🔒 Flexible privacy: subscriber-only posts, local messages, CW tags\u003c/li\u003e\n\u003cli\u003e🎨 Custom emojis, design themes, and content moderation\u003c/li\u003e\n\u003cli\u003e🛡️ Local moderation and spam blocking - you control your space\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to join:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eGo to \u003ca href=\"https://social.potatoenergy.ru/\"\u003esocial.potatoenergy.ru\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eLog in with your Potato Energy account (via Authelia)\u003c/li\u003e\n\u003cli\u003eSet up a profile and start publishing - you are already in the federation\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eFor moderators:\u003c/strong\u003e\nTools for reporting, silencing/blocking, and federal rules are all in the admin panel.\u003c/p\u003e","title":"Mastodon: Your Federated Space"},{"content":"Mindustry: Industrial Wars 🏭 Strategic sandbox about the construction of production facilities and tactical battles.\nWhat\u0026rsquo;s on the server:\n⚙️ Complex production chains: ore → processing → logistics → army 🔫 PvE campaigns against waves of enemies and PvP battles for up to 16 players 🗺️ Map rotation: sandbox, survival, sector capture 🗳️ Card voting, pauses and restarts - democracy in action 💬 Chat synchronization with Discord: communicate in the game and from the browser How to connect:\nLaunch the current version of Mindustry Open \u0026ldquo;Multiplayer\u0026rdquo; → \u0026ldquo;Add Server\u0026rdquo; Enter the address: connect.potatoenergy.ru:6567 Connect and build! Rules: No cheating, respect timings, and coordinate in the chat. The details are on the server.\nStatus: https://status.potatoenergy.ru/history/mindustry\nAccess: connect.potatoenergy.ru:6567 • public, no registration required\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/mindustry-server/","summary":"\u003ch3 id=\"mindustry-industrial-wars-\"\u003eMindustry: Industrial Wars \u003ca href=\"https://mindustrygame.github.io/\"\u003e🏭\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eStrategic sandbox\u003c/strong\u003e about the construction of production facilities and tactical battles.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat\u0026rsquo;s on the server:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e⚙️ Complex production chains: ore → processing → logistics → army\u003c/li\u003e\n\u003cli\u003e🔫 PvE campaigns against waves of enemies and PvP battles for up to 16 players\u003c/li\u003e\n\u003cli\u003e🗺️ Map rotation: sandbox, survival, sector capture\u003c/li\u003e\n\u003cli\u003e🗳️ Card voting, pauses and restarts - democracy in action\u003c/li\u003e\n\u003cli\u003e💬 Chat synchronization with Discord: communicate in the game and from the browser\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to connect:\u003c/strong\u003e\u003c/p\u003e","title":"Mindustry: Industrial Wars on Potato Energy"},{"content":"Minecraft: Limitless World 🎮 A sandbox for creativity and shared adventures on Potato Energy.\nWhat\u0026rsquo;s on the server:\n⚡ High-performance engine (Paper) - without lags, even with redstone circuits 🔄 World auto backups every 30 minutes - progress in safety 💬 Chat synchronization with Discord: communicate in the game and from the browser 🛡️ Anti - cheat - protection against griefers and cheaters 🧩 Plug-ins for the quality of life: teleports, private territories, economy How to connect:\nLaunch Minecraft version 1.16.5 Open \u0026ldquo;Network Game\u0026rdquo; → \u0026ldquo;Add Server\u0026rdquo; Enter the address: connect.potatoenergy.ru:25565 Connect and explore! Rules: No cheating, respect other people\u0026rsquo;s buildings, and coordinate in the chat. The details are on the server.\nStatus: https://status.potatoenergy.ru/history/minecraft\nAccess: connect.potatoenergy.ru:25565 • public, registration is required at the entrance\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/minecraft-server/","summary":"\u003ch3 id=\"minecraft-limitless-world-\"\u003eMinecraft: Limitless World \u003ca href=\"https://minecraft.net/\"\u003e🎮\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eA sandbox for creativity\u003c/strong\u003e and shared adventures on Potato Energy.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat\u0026rsquo;s on the server:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e⚡ High-performance engine (Paper) - without lags, even with redstone circuits\u003c/li\u003e\n\u003cli\u003e🔄 World auto backups every 30 minutes - progress in safety\u003c/li\u003e\n\u003cli\u003e💬 Chat synchronization with Discord: communicate in the game and from the browser\u003c/li\u003e\n\u003cli\u003e🛡️ Anti - cheat - protection against griefers and cheaters\u003c/li\u003e\n\u003cli\u003e🧩 Plug-ins for the quality of life: teleports, private territories, economy\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to connect:\u003c/strong\u003e\u003c/p\u003e","title":"Minecraft: Boundless World of Potato Energy"},{"content":"Nextcloud: Your cloud ☁️ Secure storage of files with tools for work under your control.\nWhat does:\n📁 File synchronization between PC, phone and web interface ✍️ Collaborative document editing (OnlyOffice/ Collaboration) 🎥 Video calls via Talk with encryption and recording 📅 Calendars, tasks, contacts - synchronization via CardDAV/CalDAV 🔐 Data encryption on the server + two - factor authentication How to use:\nOpen cloud.potatoenergy.ru Log in with your Potato Energy account (via Authelia) Upload files, create documents, invite colleagues For administrators: Quota management, external storage, log auditing, integration with Authelia.\nStatus: https://status.potatoenergy.ru/history/nextcloud\nAccess: cloud.potatoenergy.ru • according to Potato Energy credentials\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/nextcloud/","summary":"\u003ch3 id=\"nextcloud-your-cloud-\"\u003eNextcloud: Your cloud \u003ca href=\"https://nextcloud.com/\"\u003e☁️\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eSecure storage\u003c/strong\u003e of files with tools for work under your control.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat does:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e📁 File synchronization between PC, phone and web interface\u003c/li\u003e\n\u003cli\u003e✍️ Collaborative document editing (OnlyOffice/ Collaboration)\u003c/li\u003e\n\u003cli\u003e🎥 Video calls via Talk with encryption and recording\u003c/li\u003e\n\u003cli\u003e📅 Calendars, tasks, contacts - synchronization via CardDAV/CalDAV\u003c/li\u003e\n\u003cli\u003e🔐 Data encryption on the server + two - factor authentication\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to use:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eOpen \u003ca href=\"https://cloud.potatoenergy.ru/\"\u003ecloud.potatoenergy.ru\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eLog in with your Potato Energy account (via Authelia)\u003c/li\u003e\n\u003cli\u003eUpload files, create documents, invite colleagues\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eFor administrators:\u003c/strong\u003e\nQuota management, external storage, log auditing, integration with Authelia.\u003c/p\u003e","title":"Nextcloud: Your Digital Workspace"},{"content":"Open WebUI: AI Assistant 🤖 Intelligent assistant to solve everyday tasks under your control.\nWhat does:\n🧠 Working with local and cloud LLMs (Llama, Mistral, GPT-compatible APIs) 🔍 RAG-search: download PDF/DOC/TXT - AI will respond based on the content of the document 🌐 Web search in Russian with quoting sources 🎥 Video analysis at the link: transcription + Sammari + answers to questions 📤 Exporting dialogs to Markdown/PDF, sharing chats via the link How to use:\nOpen chat.potatoenergy.ru Log in with your Potato Energy account (via Authelia) Select a model, upload a file, or ask a question, and you\u0026rsquo;re done. For advanced users: Configuring system tools, connecting external APIs, context management, and web hooks.\nStatus: https://status.potatoenergy.ru/history/open-web-ui\nAccess: chat.potatoenergy.ru • according to Potato Energy credentials\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/open-webui/","summary":"\u003ch3 id=\"open-webui-ai-assistant-\"\u003eOpen WebUI: AI Assistant \u003ca href=\"https://github.com/open-webui/open-webui\"\u003e🤖\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eIntelligent assistant\u003c/strong\u003e to solve everyday tasks under your control.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat does:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e🧠 Working with local and cloud LLMs (Llama, Mistral, GPT-compatible APIs)\u003c/li\u003e\n\u003cli\u003e🔍 RAG-search: download PDF/DOC/TXT - AI will respond based on the content of the document\u003c/li\u003e\n\u003cli\u003e🌐 Web search in Russian with quoting sources\u003c/li\u003e\n\u003cli\u003e🎥 Video analysis at the link: transcription + Sammari + answers to questions\u003c/li\u003e\n\u003cli\u003e📤 Exporting dialogs to Markdown/PDF, sharing chats via the link\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to use:\u003c/strong\u003e\u003c/p\u003e","title":"Open WebUI: Your Intelligent Assistant"},{"content":"Portainer: Visual control of the infrastructure 🎛️ Control panel for all services in one place.\nWhat does:\n🐳 Manage Docker containers, images, networks, and volumes via the web interface 📦 Deployment of stacks from Docker Compose in one click 🔄 Auto-deploy from the Git repository: push to the repo → service update 💻 Web terminal and container logs - debugging access without SSH 📊 Resource monitoring: CPU, RAM, disk space in real time How to use:\nOpen the portainer.potatoenergy.ru (access is only for the admin group) Log in with your Potato Energy account (via Authelia) Select service → manage, restart, see logs For administrators: Roles and access rights, action auditing, deployment templates, integration with registers.\nAccess: portainer.potatoenergy.ru • according to Potato Energy credentials (only according to the rights of the admin group)\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/portainer/","summary":"\u003ch3 id=\"portainer-visual-control-of-the-infrastructure-\"\u003ePortainer: Visual control of the infrastructure \u003ca href=\"https://www.portainer.io/\"\u003e🎛️\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eControl panel\u003c/strong\u003e for all services in one place.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat does:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e🐳 Manage Docker containers, images, networks, and volumes via the web interface\u003c/li\u003e\n\u003cli\u003e📦 Deployment of stacks from Docker Compose in one click\u003c/li\u003e\n\u003cli\u003e🔄 Auto-deploy from the Git repository: push to the repo → service update\u003c/li\u003e\n\u003cli\u003e💻 Web terminal and container logs - debugging access without SSH\u003c/li\u003e\n\u003cli\u003e📊 Resource monitoring: CPU, RAM, disk space in real time\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to use:\u003c/strong\u003e\u003c/p\u003e","title":"Portainer: Visual Infrastructure Control"},{"content":"Prometheus: Infrastructure monitoring 📊 Warning system about problems before they occur.\nWhat controls:\n🖥️ Server metrics: CPU, RAM, disk, network via node_exporter 🌐 Service availability: blackbox-HTTP/TCP/ICMP checks 📈 Collecting metrics from applications: Nextcloud, Home Assistant, and others 🚨 Alertmanager: notifications in Telegram/Discord when thresholds are exceeded 🔍 Powerful queries via PromQL for deep analysis How it works:\nPrometheus collects metrics on a schedule (scrap) Do you see graphs in Grafana or set up your dashboards In case of an anomaly, an alert is triggered and the administrator receives a notification. For administrators: Flexible alert rules, recording rules, federation of metrics, long-term storage via Thanos.\nAccess: via Grafana (grafana.potatoenergy.ru) • according to Potato Energy credentials (management is only based on the rights of the admin group)\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/prometheus/","summary":"\u003ch3 id=\"prometheus-infrastructure-monitoring-\"\u003ePrometheus: Infrastructure monitoring \u003ca href=\"https://prometheus.io/\"\u003e📊\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eWarning system\u003c/strong\u003e about problems before they occur.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat controls:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e🖥️ Server metrics: CPU, RAM, disk, network via node_exporter\u003c/li\u003e\n\u003cli\u003e🌐 Service availability: blackbox-HTTP/TCP/ICMP checks\u003c/li\u003e\n\u003cli\u003e📈 Collecting metrics from applications: Nextcloud, Home Assistant, and others\u003c/li\u003e\n\u003cli\u003e🚨 Alertmanager: notifications in Telegram/Discord when thresholds are exceeded\u003c/li\u003e\n\u003cli\u003e🔍 Powerful queries via PromQL for deep analysis\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow it works:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ePrometheus collects metrics on a schedule (scrap)\u003c/li\u003e\n\u003cli\u003eDo you see graphs in Grafana or set up your dashboards\u003c/li\u003e\n\u003cli\u003eIn case of an anomaly, an alert is triggered and the administrator receives a notification.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eFor administrators:\u003c/strong\u003e\nFlexible alert rules, recording rules, federation of metrics, long-term storage via Thanos.\u003c/p\u003e","title":"Prometheus: Infrastructure's All-Seeing Eye"},{"content":"Terraria: Adventures [⚔️](https://terraria.org /) Cooperative server for exploration, battles and creativity.\nWhat\u0026rsquo;s on the server:\n🌍 Classic mode + expert events for experienced players ⚔️ PvE co-op: bosses, events, dungeons - more fun together 🏗️ Shared world with private buildings (TShock plugin) 🔄 World auto backups every 30 minutes - progress in safety 💬 Chat + Discord-sync: communicate in the game and from the browser How to connect:\nLaunch the current version of Terraria Open \u0026ldquo;Multiplayer\u0026rdquo; → \u0026ldquo;Join via IP\u0026rdquo; Enter the address: connect.potatoenergy.ru:7777 Connect and start the adventure! Rules: No cheating, respect other people\u0026rsquo;s buildings, don\u0026rsquo;t spam the chat. The details are on the server.\nStatus: https://status.potatoenergy.ru/history/terraria\nAccess: connect.potatoenergy.ru:7777 • public, no registration required\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/terraria-server/","summary":"\u003ch3 id=\"terraria-adventures--\"\u003eTerraria: Adventures [⚔️](\u003ca href=\"https://terraria.org\"\u003ehttps://terraria.org\u003c/a\u003e /)\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eCooperative server\u003c/strong\u003e for exploration, battles and creativity.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat\u0026rsquo;s on the server:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e🌍 Classic mode + expert events for experienced players\u003c/li\u003e\n\u003cli\u003e⚔️ PvE co-op: bosses, events, dungeons - more fun together\u003c/li\u003e\n\u003cli\u003e🏗️ Shared world with private buildings (TShock plugin)\u003c/li\u003e\n\u003cli\u003e🔄 World auto backups every 30 minutes - progress in safety\u003c/li\u003e\n\u003cli\u003e💬 Chat + Discord-sync: communicate in the game and from the browser\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow to connect:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eLaunch the current version of Terraria\u003c/li\u003e\n\u003cli\u003eOpen \u0026ldquo;Multiplayer\u0026rdquo; → \u0026ldquo;Join via IP\u0026rdquo;\u003c/li\u003e\n\u003cli\u003eEnter the address: \u003ccode\u003econnect.potatoenergy.ru:7777\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eConnect and start the adventure!\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eRules:\u003c/strong\u003e\nNo cheating, respect other people\u0026rsquo;s buildings, don\u0026rsquo;t spam the chat. The details are on the server.\u003c/p\u003e","title":"Terraria: Adventures on potato Energy"},{"content":"Traefik: Smart Router 🛠️ Your digital dispatcher, who directs requests to the necessary services.\nWhat does:\n🔐 Auto-issue and update of SSL certificates (Let\u0026rsquo;s Encrypt) 🚦 Routing by domains: grafana.*/ → Grafana, cloud.*/ → Nextcloud ⚡ Zero-downtime deployment: service updates without disconnecting connections 🧩 Middleware: authentication (Authelia), rate-limiting, redirects, compression 📊 Exporting metrics for Prometheus - real - time traffic visibility How it works:\nYou enter service.potatoenergy.ru in the browser Traefik checks the rules, applies SSL and middleware The request gets into the right container - you see the service For administrators: Dynamic configuration via Docker labels and configuration files, hot-reload without restarting, integration with Docker.\nAccess: automatically • the basis for routing all Potato Energy services\n","permalink":"https://potatoenergy.gitverse.site/potatoenergy-site/en/services/traefik/","summary":"\u003ch3 id=\"traefik-smart-router-\"\u003eTraefik: Smart Router \u003ca href=\"https://traefik.io/\"\u003e🛠️\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eYour digital dispatcher\u003c/strong\u003e, who directs requests to the necessary services.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWhat does:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e🔐 Auto-issue and update of SSL certificates (Let\u0026rsquo;s Encrypt)\u003c/li\u003e\n\u003cli\u003e🚦 Routing by domains: \u003ccode\u003egrafana.*/\u003c/code\u003e → Grafana, \u003ccode\u003ecloud.*/\u003c/code\u003e → Nextcloud\u003c/li\u003e\n\u003cli\u003e⚡ Zero-downtime deployment: service updates without disconnecting connections\u003c/li\u003e\n\u003cli\u003e🧩 Middleware: authentication (Authelia), rate-limiting, redirects, compression\u003c/li\u003e\n\u003cli\u003e📊 Exporting metrics for Prometheus - real - time traffic visibility\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eHow it works:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eYou enter \u003ccode\u003eservice.potatoenergy.ru\u003c/code\u003e in the browser\u003c/li\u003e\n\u003cli\u003eTraefik checks the rules, applies SSL and middleware\u003c/li\u003e\n\u003cli\u003eThe request gets into the right container - you see the service\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eFor administrators:\u003c/strong\u003e\nDynamic configuration via Docker labels and configuration files, hot-reload without restarting, integration with Docker.\u003c/p\u003e","title":"Traefik: Smart Router"}]