Compare commits

...

194 Commits
v1.1.3 ... main

Author SHA1 Message Date
MacRimi
11fbfda6bf Update cache.json 2025-08-13 22:46:58 +02:00
MacRimi
4f0353d0fb Create proxmox-upgrade-pve8-to-pve9-manual-guide.sh 2025-08-13 22:46:38 +02:00
MacRimi
a605d68d73 Merge branch 'main' of https://github.com/MacRimi/ProxMenux 2025-08-13 20:29:26 +02:00
MacRimi
237b7fbf1b Update cache.json 2025-08-13 20:29:24 +02:00
ProxMenuxBot
4a7e21f6b4 Update helpers_cache.json 2025-08-13 18:19:42 +00:00
MacRimi
b7017573b8 Update update-pve8.sh 2025-08-13 19:45:31 +02:00
MacRimi
a98b087c5d Update log2RAM 2025-08-13 15:55:22 +02:00
MacRimi
161c840136
Update utils.sh 2025-08-11 08:57:26 +02:00
MacRimi
4dd2abc202 Update utils.sh 2025-08-10 21:56:07 +02:00
MacRimi
cc0e9f61a7 Update utils.sh 2025-08-10 21:43:05 +02:00
MacRimi
21a658f1f4 Update utils.sh 2025-08-10 21:23:19 +02:00
MacRimi
b99f391c2a Merge branch 'main' of https://github.com/MacRimi/ProxMenux 2025-08-10 21:09:25 +02:00
MacRimi
9abe25b91a Update README.md 2025-08-10 21:09:01 +02:00
ProxMenuxBot
2531fc6dac Update helpers_cache.json 2025-08-09 12:25:42 +00:00
ProxMenuxBot
e5551cb179 Update helpers_cache.json 2025-08-09 01:05:21 +00:00
MacRimi
4728b7a8b7 Update utils.sh 2025-08-08 18:26:32 +02:00
ProxMenuxBot
2863921e15 Update helpers_cache.json 2025-08-08 12:29:54 +00:00
ProxMenuxBot
b93668edfe Update helpers_cache.json 2025-08-08 06:23:01 +00:00
ProxMenuxBot
8ae91b8c31 Update helpers_cache.json 2025-08-07 18:21:56 +00:00
MacRimi
894a23d701 Update common-functions.sh 2025-08-07 20:10:36 +02:00
MacRimi
3598906cbd Update common-functions.sh 2025-08-07 19:37:28 +02:00
MacRimi
75c12e2d4b update common funtions 2025-08-07 19:24:39 +02:00
MacRimi
d6e0519a3d Update common-functions.sh 2025-08-07 19:08:44 +02:00
MacRimi
41efc71626 Update update-pve.sh 2025-08-07 19:05:52 +02:00
MacRimi
6e3d97f472 Update common-functions.sh 2025-08-07 19:05:23 +02:00
MacRimi
9d58d02522 Update proxmox_update.sh 2025-08-07 18:11:32 +02:00
MacRimi
fe86396b21 Update proxmox_update.sh 2025-08-07 18:08:37 +02:00
MacRimi
97994f7632 Update update-pve.sh 2025-08-07 17:58:24 +02:00
MacRimi
33d63457b3 Update update-pve8.sh 2025-08-07 17:58:00 +02:00
MacRimi
ed36d9e953
Update proxmox_update.sh 2025-08-07 15:49:22 +02:00
MacRimi
9a478d74d2
Update proxmox_update.sh 2025-08-07 15:45:46 +02:00
MacRimi
72d72544a4
Update update-pve.sh 2025-08-07 15:31:03 +02:00
MacRimi
4bbbe81182
Update update-pve.sh 2025-08-07 15:05:54 +02:00
MacRimi
a0af0c2492
Update update-pve.sh 2025-08-07 14:47:58 +02:00
MacRimi
ce7d3e4702
Update update-pve.sh 2025-08-07 14:30:48 +02:00
MacRimi
1bb4ca8541
Update common-functions.sh 2025-08-07 14:23:33 +02:00
MacRimi
ea65445772
Update update-pve.sh 2025-08-07 14:02:02 +02:00
MacRimi
972db8fcea
Update update-pve8.sh 2025-08-07 13:04:05 +02:00
MacRimi
a3c12631f0
Update auto_post_install.sh 2025-08-07 11:16:24 +02:00
MacRimi
3cadfd08d8 Update install_proxmenux.sh 2025-08-07 08:04:04 +02:00
MacRimi
104f3de013 Update version.txt 2025-08-06 23:10:08 +02:00
MacRimi
713b41bd52 Update CHANGELOG.md 2025-08-06 23:09:36 +02:00
MacRimi
253093fa2f Update update-pve.sh 2025-08-06 23:08:53 +02:00
MacRimi
f36af5af64 Update update-pve.sh 2025-08-06 22:37:13 +02:00
MacRimi
97b6c0e44d Delete common-functions_.sh 2025-08-06 22:14:12 +02:00
MacRimi
c4f6dabd4d Update system_utils.sh 2025-08-06 22:02:40 +02:00
MacRimi
d1c8aeb25d update pve 8 2025-08-06 22:01:33 +02:00
MacRimi
6e1cb2e0fe Update common-functions.sh 2025-08-06 21:47:53 +02:00
MacRimi
da9762f60e Update update-pve.sh 2025-08-06 21:45:09 +02:00
MacRimi
27affdec14 Update common-functions.sh 2025-08-06 21:17:06 +02:00
MacRimi
433a19e46a Update customizable_post_install.sh 2025-08-06 20:10:38 +02:00
MacRimi
da9db9d3d1 Update update-pve.sh 2025-08-06 20:09:01 +02:00
MacRimi
ed4b0eba2f Update auto_post_install.sh 2025-08-06 20:04:52 +02:00
MacRimi
615aecf80f Update common funtions 2025-08-06 20:04:12 +02:00
MacRimi
4622d1a610 Update update-pve8.sh 2025-08-06 19:31:15 +02:00
MacRimi
f1b80d8f57 Update customizable_post_install.sh 2025-08-06 19:22:11 +02:00
MacRimi
e76e303383 Update update-pve8.sh 2025-08-06 19:20:03 +02:00
MacRimi
97133c3fcb Update auto_post_install.sh 2025-08-06 19:17:45 +02:00
MacRimi
450610b6e6 Update update-pve8.sh 2025-08-06 19:14:32 +02:00
MacRimi
4dc3fd92cc Update update-pve8.sh 2025-08-06 19:04:32 +02:00
MacRimi
f4b5e7c044 Create update-pve8.sh 2025-08-06 18:47:41 +02:00
MacRimi
6c0b2a468d Update common-functions.sh 2025-08-06 18:47:16 +02:00
MacRimi
e33f724f1b Create common-functions.sh 2025-08-06 18:17:51 +02:00
MacRimi
b0d5562917 Update remove-banner-pve8.sh 2025-08-06 17:45:22 +02:00
MacRimi
eecf7a2194 Update remove subscription banner PVE 8.4.9 2025-08-06 17:17:00 +02:00
MacRimi
54fd8a0332 Update remove-banner-pve8.sh 2025-08-06 17:12:16 +02:00
MacRimi
b6ca91980b global update 2025-08-06 16:50:16 +02:00
MacRimi
6af7e2d749
Update remove-banner-pve8.sh 2025-08-06 15:27:26 +02:00
MacRimi
86d334c204
Update remove-banner-pve9.sh 2025-08-06 15:21:31 +02:00
MacRimi
585a4fa449
Update remove-banner-pve9.sh 2025-08-06 15:19:56 +02:00
MacRimi
7438073e7e
Update remove-banner-pve8.sh 2025-08-06 15:19:33 +02:00
MacRimi
6e808ae35a
Update remove-banner-pve8.sh 2025-08-06 14:32:14 +02:00
MacRimi
99ec64e852
Create remove-banner-pve9.sh 2025-08-06 14:31:19 +02:00
MacRimi
eeac63c0a5
Create remove-banner-pve8.sh 2025-08-06 14:23:22 +02:00
MacRimi
5d5a3c3301 update funtions to pve9 2025-08-05 20:30:29 +02:00
ProxMenuxBot
31e9730236 Update helpers_cache.json 2025-08-05 12:31:00 +00:00
MacRimi
69b32a02ff
Update utils.sh 2025-08-05 09:46:30 +02:00
ProxMenuxBot
a222df8176 Update helpers_cache.json 2025-08-04 12:30:37 +00:00
MacRimi
7f4c99be60
Update customizable_post_install.sh 2025-08-04 11:29:43 +02:00
MacRimi
ccff657a62
Update auto_post_install.sh 2025-08-04 11:29:28 +02:00
MacRimi
fb258499e1
Update customizable_post_install.sh 2025-08-04 11:22:10 +02:00
MacRimi
79c6d6c742
Update customizable_post_install.sh 2025-08-04 11:20:38 +02:00
MacRimi
80d9d5480c
Update customizable_post_install.sh 2025-08-04 11:19:41 +02:00
MacRimi
958a553922
Update auto_post_install.sh 2025-08-04 11:19:27 +02:00
MacRimi
a44bbc3513
Update customizable_post_install.sh 2025-08-04 11:16:52 +02:00
MacRimi
d7f2f4a3e7
Update customizable_post_install.sh 2025-08-04 11:15:59 +02:00
MacRimi
073566a23e
Update auto_post_install.sh 2025-08-04 11:11:14 +02:00
MacRimi
590aecfcf1
Update customizable_post_install.sh 2025-08-04 11:11:00 +02:00
MacRimi
77ab52310e
Update auto_post_install.sh 2025-08-04 11:03:31 +02:00
MacRimi
2c2ccddbe4
Update customizable_post_install.sh 2025-08-04 11:02:23 +02:00
MacRimi
87062db9d5
Update customizable_post_install.sh 2025-08-04 10:44:58 +02:00
MacRimi
b74701dbc5
Update system_utils.sh 2025-08-04 08:52:55 +02:00
MacRimi
a88db8830b
Update customizable_post_install.sh 2025-08-04 08:34:40 +02:00
ProxMenuxBot
36cd83c796 Update helpers_cache.json 2025-08-04 01:16:40 +00:00
MacRimi
a039c93c05
Update customizable_post_install.sh 2025-08-03 23:13:36 +02:00
MacRimi
57b4ade3be
Update auto_post_install.sh 2025-08-03 23:12:32 +02:00
MacRimi
87ce6cfa98
Update auto_post_install.sh 2025-08-03 23:08:06 +02:00
MacRimi
6a99c8c81d
Update customizable_post_install.sh 2025-08-03 23:06:31 +02:00
ProxMenuxBot
46e8188d5a Update helpers_cache.json 2025-08-02 18:19:25 +00:00
MacRimi
3c990df1fe
Actualizar main_menu.sh 2025-08-02 12:02:10 +02:00
ProxMenuxBot
8969bc5aa6 Update helpers_cache.json 2025-08-02 01:07:27 +00:00
MacRimi
45e8ca8d42
Update customizable_post_install.sh 2025-08-01 08:28:12 +02:00
MacRimi
39930153c9 Update customizable_post_install.sh 2025-08-01 07:25:44 +02:00
MacRimi
5890e46db3 Update auto_post_install.sh 2025-08-01 06:57:21 +02:00
MacRimi
c5c06a08ba Merge branch 'main' of https://github.com/MacRimi/ProxMenux 2025-08-01 06:50:09 +02:00
MacRimi
2a0e677a89 Update proxmox_update.sh 2025-08-01 06:50:07 +02:00
ProxMenuxBot
8f7a968dc9 Update helpers_cache.json 2025-07-31 18:21:21 +00:00
MacRimi
20cfc50448 Update select_linux_iso.sh 2025-07-31 19:39:03 +02:00
MacRimi
4bf019ec7e Update jd2.sh 2025-07-31 19:11:18 +02:00
MacRimi
57fe45484c Update jd2.sh 2025-07-31 18:00:30 +02:00
MacRimi
7744f4ed76 Update jd2.sh 2025-07-31 17:43:14 +02:00
MacRimi
a43e81e229
Update jd2.sh 2025-07-31 15:14:00 +02:00
MacRimi
f6ad7e250b
Update jd2.sh 2025-07-31 14:45:02 +02:00
MacRimi
0f2b0482ec
Create jd2.sh 2025-07-31 14:27:12 +02:00
MacRimi
21d850d39e
Rename jd2.sh to jd2_.sh 2025-07-31 14:26:46 +02:00
MacRimi
d3f2e42301
Create jd2.sh 2025-07-31 12:50:19 +02:00
MacRimi
df68154f10 Update disk-passthrough_ct.sh 2025-07-30 18:43:54 +02:00
MacRimi
f8ebf03afd Update system_utils.sh 2025-07-30 18:18:13 +02:00
MacRimi
23f8b97319 Update customizable_post_install.sh 2025-07-30 17:59:12 +02:00
MacRimi
d712054353 Update customizable_post_install.sh 2025-07-30 17:55:51 +02:00
MacRimi
58da896b14 Update system_utils.sh 2025-07-30 17:54:15 +02:00
MacRimi
8db57bda6e Update install utilities 2025-07-30 17:34:44 +02:00
MacRimi
53f29ec710 Merge branch 'main' of https://github.com/MacRimi/ProxMenux 2025-07-29 22:22:38 +02:00
MacRimi
43a8fc0e86 Update customizable_post_install.sh 2025-07-29 22:22:36 +02:00
ProxMenuxBot
7f2adb068e Update helpers_cache.json 2025-07-29 18:21:40 +00:00
MacRimi
218ae9f9bf Update uninstall-tools.sh 2025-07-29 20:15:55 +02:00
MacRimi
350c03874d Update customizable_post_install.sh 2025-07-29 20:09:54 +02:00
MacRimi
575c0e5bf9 Update customizable_post_install.sh 2025-07-29 19:58:49 +02:00
ProxMenuxBot
3a890ba2c7 Update helpers_cache.json 2025-07-29 12:30:07 +00:00
ProxMenuxBot
2a345f4869 Update helpers_cache.json 2025-07-28 12:30:05 +00:00
ProxMenuxBot
658ebbd84d Update helpers_cache.json 2025-07-27 12:26:49 +00:00
ProxMenuxBot
0c54ade367 Update helpers_cache.json 2025-07-26 17:08:21 +00:00
ProxMenuxBot
f16ba64026 Update helpers_cache.json 2025-07-25 12:28:04 +00:00
ProxMenuxBot
d72127aaeb Update helpers_cache.json 2025-07-25 01:09:29 +00:00
ProxMenuxBot
40e0b1291c Update helpers_cache.json 2025-07-24 18:20:25 +00:00
MacRimi
0fae7f0166 Merge branch 'main' of https://github.com/MacRimi/ProxMenux 2025-07-22 22:34:12 +02:00
MacRimi
6f916a4c32 Update customizable_post_install.sh 2025-07-22 22:33:58 +02:00
ProxMenuxBot
41979d5389 Update helpers_cache.json 2025-07-22 18:20:56 +00:00
MacRimi
0d51205bd6 Update customizable_post_install.sh 2025-07-22 19:10:35 +02:00
MacRimi
416dd52a30 Update fastfetch 2025-07-22 19:03:41 +02:00
MacRimi
850e45b9a5 Update uninstall-tools.sh 2025-07-22 18:54:14 +02:00
MacRimi
040d2ca7f6 Update customizable_post_install.sh 2025-07-22 18:39:48 +02:00
ProxMenuxBot
e173072622 Update helpers_cache.json 2025-07-22 12:29:23 +00:00
MacRimi
991dd80382
Update select_linux_iso.sh 2025-07-22 12:02:38 +02:00
MacRimi
5fc5d02134
Update auto_post_install.sh 2025-07-22 09:27:40 +02:00
MacRimi
0f51256add
Update auto_post_install.sh 2025-07-22 09:22:59 +02:00
ProxMenuxBot
a78860dbc4 Update helpers_cache.json 2025-07-21 18:20:56 +00:00
MacRimi
f655a3c52d Update auto_post_install.sh 2025-07-20 20:03:12 +02:00
MacRimi
b69aebd5be update post-install menu 2025-07-20 19:36:59 +02:00
MacRimi
769a7c391f
Update customizable_post_install.sh 2025-07-20 14:18:06 +02:00
MacRimi
9a4d55aa36 Update customizable_post_install.sh 2025-07-20 12:34:21 +02:00
MacRimi
e776acfbab Update CHANGELOG.md 2025-07-20 12:08:37 +02:00
MacRimi
b4f58286b4
Update network_menu.sh 2025-07-20 11:50:04 +02:00
MacRimi
59779cc931
Update network_menu.sh 2025-07-20 11:46:26 +02:00
MacRimi
567bcecc80
Update network_menu.sh 2025-07-20 11:42:25 +02:00
MacRimi
0ca87dc29b
Update network_menu.sh 2025-07-20 11:38:54 +02:00
MacRimi
6e0824e357
Update customizable_post_install.sh 2025-07-20 11:27:08 +02:00
MacRimi
9a8a620658
Update uninstall-tools.sh 2025-07-20 11:17:33 +02:00
MacRimi
eb1db3120d
Update auto_post_install.sh 2025-07-20 10:55:04 +02:00
MacRimi
98a9225c32
Update customizable_post_install.sh 2025-07-20 02:27:46 +02:00
MacRimi
1b8fb766a8
Update auto_post_install.sh 2025-07-20 02:26:26 +02:00
MacRimi
c28ef3ec3b
Update auto_post_install.sh 2025-07-20 02:12:27 +02:00
MacRimi
fab3f0630c
Update customizable_post_install.sh 2025-07-20 02:09:11 +02:00
MacRimi
d2499ad157
Update customizable_post_install.sh 2025-07-20 01:55:47 +02:00
MacRimi
724a37bbf4
Update auto_post_install.sh 2025-07-20 01:51:14 +02:00
MacRimi
c5f1c30b1c Update disk-passthrough_ct.sh 2025-07-19 18:28:28 +02:00
MacRimi
e90363df71
Update customizable_post_install.sh 2025-07-19 17:43:31 +02:00
MacRimi
0932008619
Update auto_post_install.sh 2025-07-19 17:40:52 +02:00
MacRimi
a24e00ad5a
Update auto_post_install.sh 2025-07-19 17:25:43 +02:00
MacRimi
fab938055f
Update auto_post_install.sh 2025-07-19 17:19:06 +02:00
MacRimi
b2026b0dac
Update auto_post_install.sh 2025-07-19 17:06:33 +02:00
MacRimi
c1c742084e
Update auto_post_install.sh 2025-07-19 17:02:38 +02:00
MacRimi
7140f590cf
Update uninstall-tools.sh 2025-07-19 16:52:13 +02:00
MacRimi
dcc26ad666
Update customizable_post_install.sh 2025-07-19 16:43:14 +02:00
MacRimi
70f1ecad49
Update customizable_post_install.sh 2025-07-19 16:38:55 +02:00
ProxMenuxBot
03c7383b54 Update helpers_cache.json 2025-07-17 18:20:17 +00:00
ProxMenuxBot
d3734971cc Update helpers_cache.json 2025-07-14 18:20:49 +00:00
ProxMenuxBot
cff8358b3e Update helpers_cache.json 2025-07-14 12:28:40 +00:00
ProxMenuxBot
42d691c4ce Update helpers_cache.json 2025-07-13 18:18:07 +00:00
MacRimi
33dcbe8b5a Update install_coral_lxc.sh 2025-07-12 18:34:49 +02:00
MacRimi
980c7a4390 Update uupdump_creator.sh 2025-07-11 21:20:18 +02:00
MacRimi
1b7f881d5a Update uupdump_creator.sh 2025-07-11 20:20:32 +02:00
MacRimi
8635e2cf67 Update uupdump_creator.sh 2025-07-11 20:13:33 +02:00
MacRimi
e36bc8bab2 Update uupdump_creator.sh 2025-07-11 20:09:16 +02:00
MacRimi
693da7733f Update uupdump_creator.sh 2025-07-11 19:59:34 +02:00
MacRimi
6b6128d92d Update uupdump_creator.sh 2025-07-11 17:28:02 +02:00
MacRimi
64586a44b4 Update customizable_post_install.sh 2025-07-10 19:25:50 +02:00
MacRimi
2d28ecca32 Update network_menu.sh 2025-07-10 19:16:16 +02:00
MacRimi
92f3edb337 Update network_menu.sh 2025-07-10 19:11:32 +02:00
MacRimi
32f8edecdd Update network_menu.sh 2025-07-10 17:09:59 +02:00
MacRimi
14b061cd28
Update cache.json 2025-07-10 12:37:59 +02:00
MacRimi
aeb90cbdd2
Update network_menu.sh 2025-07-10 12:31:51 +02:00
MacRimi
e2a0b627b2 Update cache.json 2025-07-09 22:29:03 +02:00
MacRimi
de5eb0d914 Update version.txt 2025-07-09 22:07:26 +02:00
27 changed files with 4265 additions and 1660 deletions

View File

@ -1,3 +1,93 @@
## 2025-08-06
### New version v1.1.4
### Added
- **Proxmox 9 Compatibility Preparation**
This version prepares **ProxMenux** for the upcoming **Proxmox VE 9**:
- The function to add the official Proxmox repositories now supports the new `.sources` format used in Proxmox 9, while maintaining backward compatibility with Proxmox 8.
- Banner removal is now optionally supported for Proxmox 9.
- **xshok-proxmox Detection**
Added a check to detect if the `xshok-proxmox` post-install script has already been executed.
If detected, a warning is shown to avoid conflicting adjustments:
```
It appears that you have already executed the xshok-proxmox post-install script on this system.
If you continue, some adjustments may be duplicated or conflict with those already made by xshok.
Do you want to continue anyway?
```
---
### Improved
- **Banner Removal (Proxmox 8.4.9+)**
Updated the logic for removing the subscription banner in **Proxmox 8.4.9**, due to changes in `proxmoxlib.js`.
- **LXC Disk Passthrough (Persistent UUID)**
The function to add a physical disk to an LXC container now uses **UUID-based persistent paths**.
This ensures that disks remain correctly mounted, even if the `/dev/sdX` order changes due to new hardware.
```bash
PERSISTENT_DISK=$(get_persistent_path "$DISK")
if [[ "$PERSISTENT_DISK" != "$DISK" ]] ...
```
- **System Utilities Installer**
Now checks whether APT sources are available before installing selected tools.
If a new Proxmox installation has no active repos, it will **automatically add the default sources** to avoid installation failure.
- **IOMMU Activation on ZFS Systems**
The function that enables IOMMU for passthrough now verifies existing kernel parameters to avoid duplication if the user has already configured them manually.
---
### Fixed
- Minor code cleanup and improved runtime performance across several modules.
## 2025-07-20
### Changed
- **Subscription Banner Removal (Proxmox 8.4.5+)**
Improved the `remove_subscription_banner` function to ensure compatibility with Proxmox 8.4.5, where the banner removal method was failing after clean installations.
- **Improved Log2RAM Detection**
In both the automatic and customizable post-install scripts, the logic for Log2RAM installation has been improved.
Now it correctly detects if Log2RAM is already configured and avoids triggering errors or reconfiguration.
- **Optimized Figurine Installation**
The `install_figurine` function now avoids duplicating `.bashrc` entries if the customization for the root prompt already exists.
### Added
- **New Function: Persistent Network Interface Naming**
Added a new function `setup_persistent_network` to create stable network interface names using `.link` files based on MAC addresses.
This avoids unpredictable renaming (e.g., `enp2s0` becoming `enp3s0`) when hardware changes, PCI topology shifts, or passthrough configurations are applied.
**Why use `.link` files?**
Because predictable interface names in `systemd` can change with hardware reordering or replacement. Using static `.link` files bound to MAC addresses ensures consistency, especially on systems with multiple NICs or passthrough setups.
Special thanks to [@Andres_Eduardo_Rojas_Moya] for contributing the persistent
network naming function and for the original idea.
```bash
[Match]
MACAddress=XX:XX:XX:XX:XX:XX
[Link]
Name=eth0
```
## 2025-07-01
### New version v1.1.3

View File

@ -59,7 +59,7 @@ Then, follow the on-screen options to manage your Proxmox server efficiently.
## 📌 System Requirements
🖥 **Compatible with:**
- Proxmox VE 8.x**
- Proxmox VE 8.x and 9.x
📦 **Dependencies:**
- `bash`, `curl`, `wget`, `jq`, `whiptail`, `python3-venv` (These dependencies are installed automatically during setup.)

View File

@ -498,6 +498,8 @@ install_translation_version() {
show_installation_options() {
local current_install_type
current_install_type=$(check_existing_installation)
local pve_version
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
local menu_title="ProxMenux Installation"
local menu_text="Choose installation type:"
@ -516,9 +518,29 @@ show_installation_options() {
esac
fi
INSTALL_TYPE=$(whiptail --backtitle "ProxMenux" --title "$menu_title" --menu "\n$menu_text" 14 70 2 \
"1" "Normal Version (English only)" \
"2" "Translation Version (Multi-language support)" 3>&1 1>&2 2>&3)
if [[ "$pve_version" -ge 9 ]]; then
INSTALL_TYPE=$(whiptail --backtitle "ProxMenux" --title "$menu_title" --menu "\n$menu_text" 14 70 2 \
"1" "Normal Version (English only)" 3>&1 1>&2 2>&3)
if [ -z "$INSTALL_TYPE" ]; then
msg_warn "Installation cancelled."
exit 1
fi
else
INSTALL_TYPE=$(whiptail --backtitle "ProxMenux" --title "$menu_title" --menu "\n$menu_text" 14 70 2 \
"1" "Normal Version (English only)" \
"2" "Translation Version (Multi-language support)" 3>&1 1>&2 2>&3)
if [ -z "$INSTALL_TYPE" ]; then
msg_warn "Installation cancelled."
exit 1
fi
fi
if [ -z "$INSTALL_TYPE" ]; then
msg_warn "Installation cancelled."

View File

@ -1908,6 +1908,663 @@
"de": "Automatisiertes Post-Installationsskript",
"it": "Script automatico post-installazione",
"pt": "Script automatizado pós-instalação"
},
"Network Management - SAFE MODE": {
"es": "Gestión de red - Modo seguro",
"fr": "Gestion du réseau - Mode sans risque",
"de": "Netzwerkverwaltung - SICHERER MODUS",
"it": "Gestione rete - Modalità sicura",
"pt": "Gerenciamento de rede - Modo seguro"
},
"Show Interface Details": {
"es": "Mostrar detalles de la interfaz",
"fr": "Afficher les détails de l'interface",
"de": "Schnittstellendetails anzeigen",
"it": "Mostra dettagli dell'interfaccia",
"pt": "Mostrar detalhes da interface"
},
"Show Bridge Status": {
"es": "Mostrar estado del puente",
"fr": "Afficher l'état du pont",
"de": "Bridge-Status anzeigen",
"it": "Mostra stato del bridge",
"pt": "Mostrar status da ponte"
},
"Show Routing Table": {
"es": "Mostrar tabla de enrutamiento",
"fr": "Afficher la table de routage",
"de": "Routing-Tabelle anzeigen",
"it": "Mostra tabella di routing",
"pt": "Mostrar tabela de roteamento"
},
"Test Connectivity": {
"es": "Probar conectividad",
"fr": "Tester la connectivité",
"de": "Konnektivität testen",
"it": "Verifica la connettività",
"pt": "Testar conectividade"
},
"Advanced Diagnostics": {
"es": "Diagnóstico avanzado",
"fr": "Diagnostic avancé",
"de": "Erweiterte Diagnose",
"it": "Diagnostica avanzata",
"pt": "Diagnóstico avançado"
},
"Analyze Bridge Configuration": {
"es": "Analizar configuración del puente",
"fr": "Analyser la configuration du pont",
"de": "Bridge-Konfiguration analysieren",
"it": "Analizza configurazione bridge",
"pt": "Analisar configuração da ponte"
},
"Analyze Network Configuration": {
"es": "Analizar configuración de red",
"fr": "Analyser la configuration du réseau",
"de": "Netzwerkkonfiguration analysieren",
"it": "Analizza configurazione di rete",
"pt": "Analisar configuração de rede"
},
"Restart Network Service": {
"es": "Reiniciar servicio de red",
"fr": "Redémarrer le service réseau",
"de": "Netzwerkdienst neu starten",
"it": "Riavvia servizio di rete",
"pt": "Reiniciar serviço de rede"
},
"Show Network Config File": {
"es": "Mostrar archivo de configuración de red",
"fr": "Afficher le fichier de configuration réseau",
"de": "Netzwerkkonfigurationsdatei anzeigen",
"it": "Mostra file di configurazione di rete",
"pt": "Mostrar arquivo de configuração de rede"
},
"Create Network Backup": {
"es": "Crear copia de seguridad de red",
"fr": "Créer une sauvegarde du réseau",
"de": "Netzwerk-Backup erstellen",
"it": "Crea backup della rete",
"pt": "Criar backup de rede"
},
"Restore Network Backup": {
"es": "Restaurar copia de seguridad de red",
"fr": "Restaurer la sauvegarde du réseau",
"de": "Netzwerk-Backup wiederherstellen",
"it": "Ripristina backup della rete",
"pt": "Restaurar backup de rede"
},
"Analyzing Bridge Configuration - READ ONLY MODE": {
"es": "Analizando configuración del puente - Solo lectura",
"fr": "Analyse de la configuration du pont - Mode lecture seule",
"de": "Bridge-Konfiguration analysieren - Nur-Lese-Modus",
"it": "Analisi configurazione bridge - Solo lettura",
"pt": "Analisando configuração da ponte - Modo somente leitura"
},
"BRIDGE CONFIGURATION ANALYSIS": {
"es": "Análisis de configuración del puente",
"fr": "Analyse de la configuration du pont",
"de": "Bridge-Konfigurationsanalyse",
"it": "Analisi configurazione bridge",
"pt": "Análise de configuração da ponte"
},
"Bridge": {
"es": "Puente",
"fr": "Pont",
"de": "Bridge",
"it": "Bridge",
"pt": "Ponte"
},
"Status": {
"es": "Estado",
"fr": "Statut",
"de": "Status",
"it": "Stato",
"pt": "Status"
},
"IP": {
"es": "IP",
"fr": "IP",
"de": "IP",
"it": "IP",
"pt": "IP"
},
"Configured Ports": {
"es": "Puertos configurados",
"fr": "Ports configurés",
"de": "Konfigurierte Ports",
"it": "Porte configurate",
"pt": "Portas configuradas"
},
"Port": {
"es": "Puerto",
"fr": "Port",
"de": "Port",
"it": "Porta",
"pt": "Porta"
},
"EXISTS": {
"es": "Existe",
"fr": "Existe",
"de": "Existiert",
"it": "Esiste",
"pt": "Existe"
},
"ANALYSIS SUMMARY": {
"es": "Resumen del análisis",
"fr": "Résumé de l'analyse",
"de": "Analyse-Zusammenfassung",
"it": "Riepilogo analisi",
"pt": "Resumo da análise"
},
"Bridges analyzed": {
"es": "Puentes analizados",
"fr": "Ponts analysés",
"de": "Analysierte Bridges",
"it": "Bridge analizzati",
"pt": "Pontes analisadas"
},
"Issues found": {
"es": "Problemas encontrados",
"fr": "Problèmes trouvés",
"de": "Gefundene Probleme",
"it": "Problemi trovati",
"pt": "Problemas encontrados"
},
"Physical interfaces available": {
"es": "Interfaces físicas disponibles",
"fr": "Interfaces physiques disponibles",
"de": "Verfügbare physische Schnittstellen",
"it": "Interfacce fisiche disponibili",
"pt": "Interfaces físicas disponíveis"
},
"No bridge configuration issues found": {
"es": "No se encontraron problemas en la configuración del puente",
"fr": "Aucun problème de configuration du pont trouvé",
"de": "Keine Bridge-Konfigurationsprobleme gefunden",
"it": "Nessun problema di configurazione del bridge trovato",
"pt": "Nenhum problema encontrado na configuração da ponte"
},
"Bridge Configuration Analysis": {
"es": "Análisis de configuración del puente",
"fr": "Analyse de la configuration du pont",
"de": "Bridge-Konfigurationsanalyse",
"it": "Analisi configurazione bridge",
"pt": "Análise de configuração da ponte"
},
"Real-time network usage (iftop)": {
"es": "Uso de red en tiempo real (iftop)",
"fr": "Utilisation du réseau en temps réel (iftop)",
"de": "Echtzeit-Netzwerkauslastung (iftop)",
"it": "Utilizzo rete in tempo reale (iftop)",
"pt": "Uso de rede em tempo real (iftop)"
},
"Network monitoring tool (iptraf-ng)": {
"es": "Herramienta de monitoreo de red (iptraf-ng)",
"fr": "Outil de surveillance réseau (iptraf-ng)",
"de": "Netzwerküberwachungstool (iptraf-ng)",
"it": "Strumento di monitoraggio rete (iptraf-ng)",
"pt": "Ferramenta de monitoramento de rede (iptraf-ng)"
},
"iftop usage": {
"es": "Uso de iftop",
"fr": "Utilisation de iftop",
"de": "Verwendung von iftop",
"it": "Utilizzo di iftop",
"pt": "Uso do iftop"
},
"To exit iftop, press q": {
"es": "Para salir de iftop, pulse q",
"fr": "Pour quitter iftop, appuyez sur q",
"de": "Zum Beenden von iftop, q drücken",
"it": "Per uscire da iftop, premi q",
"pt": "Para sair do iftop, pressione q"
},
"iptraf-ng usage": {
"es": "Uso de iptraf-ng",
"fr": "Utilisation de iptraf-ng",
"de": "Verwendung von iptraf-ng",
"it": "Utilizzo di iptraf-ng",
"pt": "Uso do iptraf-ng"
},
"To exit iptraf-ng, press x": {
"es": "Para salir de iptraf-ng, pulse x",
"fr": "Pour quitter iptraf-ng, appuyez sur x",
"de": "Zum Beenden von iptraf-ng, x drücken",
"it": "Per uscire da iptraf-ng, premi x",
"pt": "Para sair do iptraf-ng, pressione x"
},
"Proxmox VE 8 to 9 Manual Upgrade Guide": {
"es": "Guía de actualización manual de Proxmox VE 8 a 9",
"fr": "Guide de mise à niveau manuelle de Proxmox VE 8 vers 9",
"de": "Manuelles Upgrade-Handbuch: Proxmox VE 8 auf 9",
"it": "Guida all'aggiornamento manuale da Proxmox VE 8 a 9",
"pt": "Guia de atualização manual do Proxmox VE 8 para 9"
},
"Source:": {
"es": "Fuente:",
"fr": "Source :",
"de": "Quelle:",
"it": "Fonte:",
"pt": "Fonte:"
},
"IMPORTANT PREREQUISITES:": {
"es": "REQUISITOS PREVIOS IMPORTANTES:",
"fr": "PRÉREQUIS IMPORTANTS :",
"de": "WICHTIGE VORAUSSETZUNGEN:",
"it": "PREREQUISITI IMPORTANTI:",
"pt": "PRÉ-REQUISITOS IMPORTANTES:"
},
"System must be updated to latest PVE 8.4+ before starting": {
"es": "El sistema debe estar actualizado a la versión PVE 8.4+ antes de comenzar",
"fr": "Le système doit être mis à jour vers PVE 8.4+ avant de commencer",
"de": "Das System muss vor dem Start auf PVE 8.4+ aktualisiert sein",
"it": "Il sistema deve essere aggiornato a PVE 8.4+ prima di iniziare",
"pt": "O sistema deve estar atualizado para PVE 8.4+ antes de começar"
},
"Use SSH or terminal access (SSH recommended)": {
"es": "Use acceso por SSH o terminal (se recomienda SSH)",
"fr": "Utilisez un accès SSH ou terminal (SSH recommandé)",
"de": "SSH- oder Terminalzugang verwenden (SSH empfohlen)",
"it": "Usa accesso SSH o terminale (consigliato SSH)",
"pt": "Use acesso por SSH ou terminal (SSH recomendado)"
},
"Use tmux or screen to avoid interruptions": {
"es": "Use tmux o screen para evitar interrupciones",
"fr": "Utilisez tmux ou screen pour éviter les interruptions",
"de": "Verwenden Sie tmux oder screen, um Unterbrechungen zu vermeiden",
"it": "Usa tmux o screen per evitare interruzioni",
"pt": "Use tmux ou screen para evitar interrupções"
},
"Have valid backups of all VMs and containers": {
"es": "Tenga copias de seguridad válidas de todas las VMs y contenedores",
"fr": "Ayez des sauvegardes valides de toutes les VM et conteneurs",
"de": "Halten Sie gültige Backups aller VMs und Container bereit",
"it": "Avere backup validi di tutte le VM e i container",
"pt": "Tenha backups válidos de todas as VMs e contêineres"
},
"At least 5GB free space on root filesystem": {
"es": "Al menos 5 GB de espacio libre en el sistema de archivos raíz",
"fr": "Au moins 5 Go despace libre sur le système de fichiers racine",
"de": "Mindestens 5 GB freier Speicherplatz auf dem Root-Dateisystem",
"it": "Almeno 5 GB di spazio libero sul filesystem root",
"pt": "Pelo menos 5 GB de espaço livre no sistema de arquivos raiz"
},
"Do not run the upgrade from the Web UI virtual console (it will disconnect)": {
"es": "No ejecute la actualización desde la consola virtual de la interfaz web (se desconectará)",
"fr": "Nexécutez pas la mise à niveau depuis la console virtuelle de linterface Web (elle se déconnectera)",
"de": "Führen Sie das Upgrade nicht über die virtuelle Konsole der Web-UI aus (die Verbindung wird getrennt)",
"it": "Non eseguire laggiornamento dalla console virtuale dellinterfaccia Web (si disconnetterà)",
"pt": "Não execute a atualização pelo console virtual da interface Web (a conexão será interrompida)"
},
"Update system to latest PVE 8.4+ (if not done already):": {
"es": "Actualizar el sistema a PVE 8.4+ (si aún no se ha hecho):",
"fr": "Mettre à jour le système vers PVE 8.4+ (si ce nest pas déjà fait) :",
"de": "System auf PVE 8.4+ aktualisieren (falls noch nicht geschehen):",
"it": "Aggiornare il sistema a PVE 8.4+ (se non già fatto):",
"pt": "Atualizar o sistema para PVE 8.4+ (se ainda não foi feito):"
},
"Or use ProxMenux update function": {
"es": "O use la función de actualización de ProxMenux",
"fr": "Ou utilisez la fonction de mise à jour de ProxMenux",
"de": "Oder verwenden Sie die Aktualisierungsfunktion von ProxMenux",
"it": "Oppure usa la funzione di aggiornamento di ProxMenux",
"pt": "Ou use a função de atualização do ProxMenux"
},
"Verify PVE version (must be 8.4.1 or newer):": {
"es": "Verificar la versión de PVE (debe ser 8.4.1 o superior):",
"fr": "Vérifier la version de PVE (doit être 8.4.1 ou plus récente) :",
"de": "PVE-Version prüfen (muss 8.4.1 oder neuer sein):",
"it": "Verificare la versione di PVE (deve essere 8.4.1 o successiva):",
"pt": "Verificar a versão do PVE (deve ser 8.4.1 ou superior):"
},
"If this node runs hyper-converged Ceph: ensure Ceph is 19.x (Squid) BEFORE upgrading PVE.": {
"es": "Si este nodo ejecuta Ceph hiperconvergente: asegúrese de que Ceph sea 19.x (Squid) ANTES de actualizar PVE.",
"fr": "Si ce nœud exécute un Ceph hyperconvergé : assurez-vous que Ceph est en 19.x (Squid) AVANT de mettre à niveau PVE.",
"de": "Wenn dieser Knoten hyperkonvergentes Ceph betreibt: Stellen Sie sicher, dass Ceph 19.x (Squid) ist, BEVOR Sie PVE aktualisieren.",
"it": "Se questo nodo esegue Ceph iperconvergente: assicurarsi che Ceph sia 19.x (Squid) PRIMA di aggiornare PVE.",
"pt": "Se este nó executa Ceph hiperconvergente: certifique-se de que o Ceph esteja em 19.x (Squid) ANTES de atualizar o PVE."
},
"If not 19.x, upgrade Ceph (Reef→Squid) first per the official guide:": {
"es": "Si no es 19.x, actualice primero Ceph (Reef→Squid) según la guía oficial:",
"fr": "Si ce nest pas 19.x, mettez dabord à niveau Ceph (Reef→Squid) selon le guide officiel :",
"de": "Wenn nicht 19.x, aktualisieren Sie Ceph zuerst (Reef→Squid) gemäß der offiziellen Anleitung:",
"it": "Se non è 19.x, aggiornare prima Ceph (Reef→Squid) secondo la guida ufficiale:",
"pt": "Se não for 19.x, atualize primeiro o Ceph (Reef→Squid) conforme o guia oficial:"
},
"Run upgrade checklist script:": {
"es": "Ejecutar el script de la lista de verificación de actualización:",
"fr": "Exécuter le script de liste de vérification de mise à niveau :",
"de": "Upgrade-Checklisten-Skript ausführen:",
"it": "Eseguire lo script della checklist di aggiornamento:",
"pt": "Executar o script da lista de verificação de atualização:"
},
"If it warns about 'systemd-boot' meta-package, remove it:": {
"es": "Si advierte sobre el metapaquete 'systemd-boot', elimínelo:",
"fr": "Sil signale le méta-paquet « systemd-boot », supprimez-le :",
"de": "Wenn vor dem Metapaket „systemd-boot“ gewarnt wird, entfernen Sie es:",
"it": "Se avvisa del metapacchetto 'systemd-boot', rimuoverlo:",
"pt": "Se alertar sobre o metapacote 'systemd-boot', remova-o:"
},
"Start terminal multiplexer (recommended):": {
"es": "Iniciar un multiplexor de terminal (recomendado):",
"fr": "Démarrer un multiplexeur de terminal (recommandé) :",
"de": "Terminal-Multiplexer starten (empfohlen):",
"it": "Avviare un multiplexer di terminale (consigliato):",
"pt": "Iniciar um multiplexador de terminal (recomendado):"
},
"# Recommended: avoids disconnection during upgrade": {
"es": "# Recomendado: evita desconexiones durante la actualización",
"fr": "# Recommandé : évite les déconnexions pendant la mise à niveau",
"de": "# Empfohlen: vermeidet Verbindungsabbrüche während des Upgrades",
"it": "# Consigliato: evita disconnessioni durante laggiornamento",
"pt": "# Recomendado: evita desconexões durante a atualização"
},
"# Alternative if you prefer screen": {
"es": "# Alternativa si prefiere screen",
"fr": "# Alternative si vous préférez screen",
"de": "# Alternative, wenn Sie screen bevorzugen",
"it": "# Alternativa se preferisci screen",
"pt": "# Alternativa se preferir screen"
},
"Update Debian repositories to Trixie:": {
"es": "Actualizar los repositorios de Debian a Trixie:",
"fr": "Mettre à jour les dépôts Debian vers Trixie :",
"de": "Debian-Repositories auf Trixie aktualisieren:",
"it": "Aggiornare i repository Debian a Trixie:",
"pt": "Atualizar os repositórios Debian para Trixie:"
},
"Update PVE enterprise repository (Only if using enterprise):": {
"es": "Actualizar el repositorio empresarial de PVE (solo si usa enterprise):",
"fr": "Mettre à jour le dépôt entreprise de PVE (uniquement si vous utilisez enterprise) :",
"de": "PVE-Enterprise-Repository aktualisieren (nur bei Verwendung von Enterprise):",
"it": "Aggiornare il repository enterprise di PVE (solo se si usa enterprise):",
"pt": "Atualizar o repositório enterprise do PVE (apenas se usar enterprise):"
},
"Skip this step if using no-subscription repository": {
"es": "Omita este paso si usa el repositorio sin suscripción",
"fr": "Ignorez cette étape si vous utilisez le dépôt sans abonnement",
"de": "Überspringen Sie diesen Schritt, wenn Sie das No-Subscription-Repository verwenden",
"it": "Saltare questo passaggio se si usa il repository senza sottoscrizione",
"pt": "Pule esta etapa se usar o repositório sem assinatura"
},
"Add new PVE 9 enterprise repository (deb822 format) (Only if using enterprise):": {
"es": "Agregar el nuevo repositorio empresarial de PVE 9 (formato deb822) (solo si usa enterprise):",
"fr": "Ajouter le nouveau dépôt entreprise de PVE 9 (format deb822) (uniquement si vous utilisez enterprise) :",
"de": "Neues PVE-9-Enterprise-Repository (deb822-Format) hinzufügen (nur bei Enterprise):",
"it": "Aggiungere il nuovo repository enterprise di PVE 9 (formato deb822) (solo se si usa enterprise):",
"pt": "Adicionar o novo repositório enterprise do PVE 9 (formato deb822) (apenas se usar enterprise):"
},
"Only if using enterprise subscription": {
"es": "Solo si utiliza suscripción empresarial",
"fr": "Uniquement si vous avez un abonnement entreprise",
"de": "Nur bei vorhandener Enterprise-Abonnement",
"it": "Solo se si dispone di una sottoscrizione enterprise",
"pt": "Apenas se você tiver assinatura enterprise"
},
"OR add new PVE 9 no-subscription repository:": {
"es": "O agregar el nuevo repositorio de PVE 9 sin suscripción:",
"fr": "OU ajouter le nouveau dépôt PVE 9 sans abonnement :",
"de": "ODER das neue PVE-9-No-Subscription-Repository hinzufügen:",
"it": "OPPURE aggiungere il nuovo repository PVE 9 senza sottoscrizione:",
"pt": "OU adicionar o novo repositório PVE 9 sem assinatura:"
},
"Only if using no-subscription repository": {
"es": "Solo si usa el repositorio sin suscripción",
"fr": "Uniquement si vous utilisez le dépôt sans abonnement",
"de": "Nur bei Verwendung des No-Subscription-Repository",
"it": "Solo se si usa il repository senza sottoscrizione",
"pt": "Apenas se usar o repositório sem assinatura"
},
"Refresh APT index and verify repositories:": {
"es": "Actualizar el índice de APT y verificar los repositorios:",
"fr": "Actualiser lindex APT et vérifier les dépôts :",
"de": "APT-Index aktualisieren und Repositories prüfen:",
"it": "Aggiornare lindice APT e verificare i repository:",
"pt": "Atualizar o índice do APT e verificar os repositórios:"
},
"Ensure there are no errors and that proxmox-ve candidate shows 9.x": {
"es": "Asegúrese de que no haya errores y de que el candidato de proxmox-ve sea 9.x",
"fr": "Assurez-vous quil ny a aucune erreur et que le candidat proxmox-ve indique 9.x",
"de": "Stellen Sie sicher, dass keine Fehler auftreten und der proxmox-ve-Kandidat 9.x anzeigt",
"it": "Assicurarsi che non vi siano errori e che il candidato di proxmox-ve sia 9.x",
"pt": "Certifique-se de que não há erros e que o candidato proxmox-ve mostre 9.x"
},
"Update Ceph repository (Only if using Ceph):": {
"es": "Actualizar el repositorio de Ceph (solo si usa Ceph):",
"fr": "Mettre à jour le dépôt Ceph (uniquement si vous utilisez Ceph) :",
"de": "Ceph-Repository aktualisieren (nur bei Verwendung von Ceph):",
"it": "Aggiornare il repository di Ceph (solo se si usa Ceph):",
"pt": "Atualizar o repositório do Ceph (apenas se usar Ceph):"
},
"Use enterprise URL if you have subscription.": {
"es": "Use la URL enterprise si dispone de suscripción.",
"fr": "Utilisez lURL enterprise si vous avez un abonnement.",
"de": "Verwenden Sie die Enterprise-URL, wenn Sie ein Abonnement haben.",
"it": "Usa lURL enterprise se hai una sottoscrizione.",
"pt": "Use a URL enterprise se tiver assinatura."
},
"Remove old repository files:": {
"es": "Eliminar los archivos de repositorio antiguos:",
"fr": "Supprimer les anciens fichiers de dépôt :",
"de": "Alte Repository-Dateien entfernen:",
"it": "Rimuovere i vecchi file di repository:",
"pt": "Remover arquivos antigos de repositório:"
},
"Also comment any remaining 'bookworm' entries in *.list if present.": {
"es": "Comente también cualquier entrada restante de bookworm en *.list si existe.",
"fr": "Commentez également toute entrée bookworm restante dans *.list si présente.",
"de": "Kommentieren Sie außerdem verbleibende bookworm-Einträge in *.list, falls vorhanden.",
"it": "Commentare anche eventuali voci bookworm rimanenti in *.list se presenti.",
"pt": "Comente também quaisquer entradas bookworm restantes em *.list, se houver."
},
"Update package index:": {
"es": "Actualizar el índice de paquetes:",
"fr": "Mettre à jour lindex des paquets :",
"de": "Paketindex aktualisieren:",
"it": "Aggiornare lindice dei pacchetti:",
"pt": "Atualizar o índice de pacotes:"
},
"Disable kernel audit messages (optional but recommended):": {
"es": "Desactivar los mensajes de auditoría del kernel (opcional pero recomendado):",
"fr": "Désactiver les messages daudit du noyau (optionnel mais recommandé) :",
"de": "Kernel-Audit-Meldungen deaktivieren (optional, aber empfohlen):",
"it": "Disabilitare i messaggi di audit del kernel (opzionale ma consigliato):",
"pt": "Desativar as mensagens de auditoria do kernel (opcional, mas recomendado):"
},
"Start the main system upgrade:": {
"es": "Iniciar la actualización principal del sistema:",
"fr": "Démarrer la mise à niveau principale du système :",
"de": "Hauptsystem-Upgrade starten:",
"it": "Avviare laggiornamento principale del sistema:",
"pt": "Iniciar a atualização principal do sistema:"
},
"This will take time. Answer prompts carefully - see notes below.": {
"es": "Esto llevará tiempo. Responda a las indicaciones con cuidado (vea las notas a continuación).",
"fr": "Cela prendra du temps. Répondez aux invites avec attention (voir les notes ci-dessous).",
"de": "Dies wird einige Zeit dauern. Beantworten Sie Rückfragen sorgfältig (siehe Hinweise unten).",
"it": "Questo richiederà tempo. Rispondi con attenzione alle richieste (vedi note sotto).",
"pt": "Isso levará tempo. Responda às solicitações com atenção (veja as notas abaixo)."
},
"UPGRADE PROMPTS - RECOMMENDED ANSWERS:": {
"es": "INDICACIONES DE ACTUALIZACIÓN - RESPUESTAS RECOMENDADAS:",
"fr": "INVITES DE MISE À NIVEAU - RÉPONSES RECOMMANDÉES :",
"de": "UPGRADE-AUFFORDERUNGEN EMPFOHLENE ANTWORTEN:",
"it": "PROMPT DI AGGIORNAMENTO - RISPOSTE CONSIGLIATE:",
"pt": "PROMPTS DE ATUALIZAÇÃO - RESPOSTAS RECOMENDADAS:"
},
"Keep current version (N)": {
"es": "Mantener la versión actual (N)",
"fr": "Conserver la version actuelle (N)",
"de": "Aktuelle Version beibehalten (N)",
"it": "Mantieni la versione corrente (N)",
"pt": "Manter a versão atual (N)"
},
"Install maintainer's version (Y)": {
"es": "Instalar la versión del mantenedor del paquete (Y)",
"fr": "Installer la version du mainteneur du paquet (Y)",
"de": "Version des Paketbetreuers installieren (Y)",
"it": "Installare la versione del maintainer del pacchetto (Y)",
"pt": "Instalar a versão do mantenedor do pacote (Y)"
},
"Keep current version (N) if modified": {
"es": "Mantener la versión actual (N) si está modificada",
"fr": "Conserver la version actuelle (N) si elle a été modifiée",
"de": "Aktuelle Version beibehalten (N), falls angepasst",
"it": "Mantieni la versione corrente (N) se modificata",
"pt": "Manter a versão atual (N) se estiver modificada"
},
"Service restarts:": {
"es": "Reinicios de servicios:",
"fr": "Redémarrages de services :",
"de": "Neustarts von Diensten:",
"it": "Riavvii dei servizi:",
"pt": "Reinicializações de serviços:"
},
"Use default (Yes)": {
"es": "Usar la opción predeterminada (Sí)",
"fr": "Utiliser loption par défaut (Oui)",
"de": "Standardoption verwenden (Ja)",
"it": "Usare lopzione predefinita (Sì)",
"pt": "Usar a opção padrão (Sim)"
},
"Press 'q' to exit": {
"es": "Presione «q» para salir",
"fr": "Appuyez sur « q » pour quitter",
"de": "Drücken Sie „q“, um zu beenden",
"it": "Premi «q» per uscire",
"pt": "Pressione «q» para sair"
},
"If booting in EFI mode with root on LVM: install GRUB for EFI": {
"es": "Si inicia en modo EFI con root en LVM: instale GRUB para EFI",
"fr": "Si vous démarrez en mode EFI avec root sur LVM : installez GRUB pour EFI",
"de": "Wenn Sie im EFI-Modus mit Root auf LVM booten: GRUB für EFI installieren",
"it": "Se lavvio è in modalità EFI con root su LVM: installare GRUB per EFI",
"pt": "Se iniciar em modo EFI com root no LVM: instale o GRUB para EFI"
},
"Per official known issues; ensures proper boot after upgrade": {
"es": "Según las incidencias conocidas oficiales, garantiza un arranque correcto tras la actualización",
"fr": "Selon les problèmes connus officiels, cela garantit un démarrage correct après la mise à niveau",
"de": "Laut den offiziellen Known Issues sorgt dies für einen ordnungsgemäßen Start nach dem Upgrade",
"it": "Secondo le note ufficiali dei problemi noti, garantisce un avvio corretto dopo laggiornamento",
"pt": "De acordo com os problemas conhecidos oficiais, garante uma inicialização correta após a atualização"
},
"Run checklist again to verify upgrade:": {
"es": "Ejecutar de nuevo la lista de verificación para comprobar la actualización:",
"fr": "Relancer la liste de vérification pour valider la mise à niveau :",
"de": "Checkliste erneut ausführen, um das Upgrade zu verifizieren:",
"it": "Eseguire nuovamente la checklist per verificare laggiornamento:",
"pt": "Executar novamente a lista de verificação para validar a atualização:"
},
"Should show fewer or no issues": {
"es": "Debería mostrar menos problemas o ninguno",
"fr": "Devrait afficher moins de problèmes, voire aucun",
"de": "Sollte weniger oder keine Probleme anzeigen",
"it": "Dovrebbe mostrare meno problemi o nessuno",
"pt": "Deve mostrar menos problemas ou nenhum"
},
"Reboot the system:": {
"es": "Reiniciar el sistema:",
"fr": "Redémarrer le système :",
"de": "System neu starten:",
"it": "Riavviare il sistema:",
"pt": "Reiniciar o sistema:"
},
"After reboot, verify PVE version:": {
"es": "Después del reinicio, verificar la versión de PVE:",
"fr": "Après le redémarrage, vérifier la version de PVE :",
"de": "Nach dem Neustart die PVE-Version prüfen:",
"it": "Dopo il riavvio, verificare la versione di PVE:",
"pt": "Após reiniciar, verificar a versão do PVE:"
},
"Should show pve-manager/9.x.x": {
"es": "Debería mostrar pve-manager/9.x.x",
"fr": "Devrait afficher pve-manager/9.x.x",
"de": "Sollte pve-manager/9.x.x anzeigen",
"it": "Dovrebbe mostrare pve-manager/9.x.x",
"pt": "Deve mostrar pve-manager/9.x.x"
},
"Optional: Modernize repository sources:": {
"es": "Opcional: Modernizar las fuentes de repositorio:",
"fr": "Optionnel : Moderniser les sources des dépôts :",
"de": "Optional: Repository-Quellen modernisieren:",
"it": "Opzionale: Modernizzare le fonti del repository:",
"pt": "Opcional: Modernizar as fontes de repositório:"
},
"Converts to deb822; keeps .list backups as .bak": {
"es": "Convierte a deb822; mantiene copias .list como .bak",
"fr": "Convertit en deb822 ; conserve les sauvegardes .list en .bak",
"de": "Konvertiert zu deb822; behält .list-Backups als .bak bei",
"it": "Converte in deb822; mantiene i backup .list come .bak",
"pt": "Converte para deb822; mantém backups .list como .bak"
},
"CLUSTER UPGRADE NOTES:": {
"es": "NOTAS DE ACTUALIZACIÓN DEL CLÚSTER:",
"fr": "NOTES DE MISE À NIVEAU DU CLUSTER :",
"de": "HINWEISE ZUM CLUSTER-UPGRADE:",
"it": "NOTE DI AGGIORNAMENTO DEL CLUSTER:",
"pt": "NOTAS DE ATUALIZAÇÃO DO CLUSTER:"
},
"Upgrade one node at a time": {
"es": "Actualizar un nodo a la vez",
"fr": "Mettre à niveau un nœud à la fois",
"de": "Jeweils nur einen Knoten aktualisieren",
"it": "Aggiornare un nodo alla volta",
"pt": "Atualizar um nó por vez"
},
"Migrate VMs away from node being upgraded": {
"es": "Migrar las VMs fuera del nodo que se está actualizando",
"fr": "Migrer les VM hors du nœud en cours de mise à niveau",
"de": "VMs vom zu aktualisierenden Knoten weg migrieren",
"it": "Migrare le VM dal nodo in aggiornamento",
"pt": "Migrar as VMs para fora do nó em atualização"
},
"Wait for each node to complete before starting next": {
"es": "Esperar a que cada nodo termine antes de empezar con el siguiente",
"fr": "Attendre que chaque nœud soit terminé avant de commencer le suivant",
"de": "Warten, bis jeder Knoten abgeschlossen ist, bevor der nächste beginnt",
"it": "Attendere che ogni nodo termini prima di iniziare il successivo",
"pt": "Aguardar cada nó concluir antes de iniciar o próximo"
},
"HA groups will be migrated to HA rules automatically": {
"es": "Los grupos de HA se migrarán automáticamente a reglas de HA",
"fr": "Les groupes HA seront migrés automatiquement vers des règles HA",
"de": "HA-Gruppen werden automatisch in HA-Regeln migriert",
"it": "I gruppi HA verranno migrati automaticamente a regole HA",
"pt": "Grupos de HA serão migrados automaticamente para regras de HA"
},
"TROUBLESHOOTING:": {
"es": "SOLUCIÓN DE PROBLEMAS:",
"fr": "DÉPANNAGE :",
"de": "FEHLERBEHEBUNG:",
"it": "RISOLUZIONE DEI PROBLEMI:",
"pt": "SOLUÇÃO DE PROBLEMAS:"
},
"If upgrade fails:": {
"es": "Si la actualización falla:",
"fr": "Si la mise à niveau échoue :",
"de": "Wenn das Upgrade fehlschlägt:",
"it": "Se laggiornamento fallisce:",
"pt": "Se a atualização falhar:"
},
"If repositories error:": {
"es": "Si hay errores de repositorios:",
"fr": "En cas derreurs de dépôts :",
"de": "Bei Repository-Fehlern:",
"it": "In caso di errori dei repository:",
"pt": "Se houver erros nos repositórios:"
},
"If 'proxmox-ve' removal warning:": {
"es": "Si aparece advertencia de eliminación de proxmox-ve:",
"fr": "Si un avertissement de suppression de proxmox-ve apparaît :",
"de": "Bei Warnung zur Entfernung von proxmox-ve:",
"it": "Se compare un avviso di rimozione di proxmox-ve:",
"pt": "Se aparecer um aviso de remoção de proxmox-ve:"
},
"Emergency recovery:": {
"es": "Recuperación de emergencia:",
"fr": "Récupération durgence :",
"de": "Notfallwiederherstellung:",
"it": "Ripristino di emergenza:",
"pt": "Recuperação de emergência:"
}
}

View File

@ -413,6 +413,18 @@
"password": null
}
},
{
"name": "Bar-Assistant",
"slug": "bar-assistant",
"desc": "Bar Assistant is all-in-one solution for managing your home bar. Compared to other recipe management software that usually tries to be more for general use, Bar Assistant is made specifically for managing cocktail recipes. This means that there are a lot of cocktail-oriented features, like ingredient substitutes, first-class ingredients, ABV calculations, unit switching and more..",
"script": "ct/bar-assistant.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/bar-assistant.sh",
"categories": [
24
],
"notes": [],
"type": "ct"
},
{
"name": "Barcode Buddy",
"slug": "barcode-buddy",
@ -549,24 +561,6 @@
],
"type": "ct"
},
{
"name": "Calibre-Web",
"slug": "calibre-web",
"desc": "Calibre-Web is a web app for browsing, reading and downloading eBooks stored in a Calibre database.",
"script": "ct/calibre-web.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/calibre-web.sh",
"categories": [
11
],
"notes": [
"Add Calibre-Web Extras via `update`"
],
"type": "ct",
"default_credentials": {
"username": "admin",
"password": "admin123"
}
},
{
"name": "CasaOS",
"slug": "casaos",
@ -650,6 +644,18 @@
],
"type": "pve"
},
{
"name": "Cleanuparr",
"slug": "cleanuparr",
"desc": "Cleanuparr is a tool for automating the cleanup of unwanted or blocked files in Sonarr, Radarr, and supported download clients like qBittorrent, Transmission, and Deluge. It removes incomplete, blocked, or malicious downloads and can trigger replacement searches to ensure your media library stays complete and up-to-date.",
"script": "ct/cleanuparr.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/cleanuparr.sh",
"categories": [
14
],
"notes": [],
"type": "ct"
},
{
"name": "Cloudflare-DDNS",
"slug": "cloudflare-ddns",
@ -679,6 +685,20 @@
],
"type": "ct"
},
{
"name": "Cloudreve",
"slug": "cloudreve",
"desc": "Cloudreve is an open-source, community-driven cloud storage system that provides file sharing, synchronization, and management features. It supports a wide range of storage backends and integrates with various notification and logging platforms.",
"script": "ct/cloudreve.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/cloudreve.sh",
"categories": [
12
],
"notes": [
"After Installation: Register your user -> Login -> Dashboard -> Accept Primary URL."
],
"type": "ct"
},
{
"name": "Cockpit",
"slug": "cockpit",
@ -988,7 +1008,7 @@
{
"name": "Docmost",
"slug": "docmost",
"desc": "Open-source collaborative wiki and documentation software Create, collaborate, and share knowledge seamlessly with Docmost. Ideal for managing your wiki, knowledge-base, documentation and a lot more.",
"desc": "Open-source collaborative wiki and documentation software. Create, collaborate, and share knowledge seamlessly with Docmost. Ideal for managing your wiki, knowledge-base, documentation and a lot more.",
"script": "ct/docmost.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/docmost.sh",
"categories": [
@ -1618,7 +1638,8 @@
4
],
"notes": [
"Configuration settings: `/etc/headscale/config.yaml`"
"Configuration settings: `/etc/headscale/config.yaml`",
"Access headscale-admin UI via `http://<LXC-IP>/admin/`"
],
"type": "ct"
},
@ -1675,23 +1696,6 @@
"notes": [],
"type": "ct"
},
{
"name": "Home Assistant Core",
"slug": "homeassistant-core",
"desc": "A standalone installation of Home Assistant Core refers to a setup where the Home Assistant Core software is installed directly on a device or operating system, without the use of Docker containers. This provides a simpler, but less flexible and scalable solution, as the software is tightly coupled with the underlying system.",
"script": "ct/homeassistant-core.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/homeassistant-core.sh",
"categories": [
16
],
"notes": [
"If the LXC is created Privileged, the script will automatically set up USB passthrough.",
"Requires PVE 8.2.2 with kernel 6.8.4-3-pve or newer",
"Deprecation-Warning: This Core-based setup will be deprecated by August 2025. Use Home Assistant OS is strongly recommended to ensure long-term stability and updates.",
"config path: `/root/.homeassistant`"
],
"type": "ct"
},
{
"name": "Home Assistant Container",
"slug": "homeassistant",
@ -1718,9 +1722,7 @@
"categories": [
24
],
"notes": [
".env file location: `/opt/.env`"
],
"notes": [],
"type": "ct"
},
{
@ -1768,6 +1770,20 @@
],
"type": "ct"
},
{
"name": "HortusFox",
"slug": "hortusfox",
"desc": "HortusFox is a collaborative plant management system for plant enthusiasts. Manage, document and track your entire plant collection \u2013 self-hosted and privacy-friendly.",
"script": "ct/hortusfox.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/hortusfox.sh",
"categories": [
24
],
"notes": [
"Login Credentials : `cat ~/hortusfox.creds`"
],
"type": "ct"
},
{
"name": "Proxmox VE Host Backup",
"slug": "host-backup",
@ -1937,6 +1953,25 @@
"notes": [],
"type": "ct"
},
{
"name": "Jeedom",
"slug": "jeedom",
"desc": "Jeedom is a home automation system that is free, open, and cloudless. It allows users to manage and automate various aspects of their homes by creating objects, installing plugins for added functionalities, and connecting to a Market account for services. It also supports direct access URLs and user management.",
"script": "ct/jeedom.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/jeedom.sh",
"categories": [
16
],
"notes": [
"WARNING: Installation sources scripts outside of Community Scripts repo. Please check the source before installing.",
"Only OS packages are updateable. To update Jeedom, please use the web interface."
],
"type": "ct",
"default_credentials": {
"username": "admin",
"password": "admin"
}
},
{
"name": "Jellyfin Media Server",
"slug": "jellyfin",
@ -2084,9 +2119,14 @@
],
"notes": [
"First start can take a few minutes",
"This script requires some extra steps after the installation, Please checkout the `https://github.com/community-scripts/ProxmoxVE/discussions/193`"
"This script requires some extra steps after the installation, Please checkout the `https://github.com/community-scripts/ProxmoxVE/discussions/193`",
"When updating, if you had modified cache-ispn.xml: Re-apply your changes to the new file, otherwise leave it unchanged."
],
"type": "ct"
"type": "ct",
"default_credentials": {
"username": "tmpadm",
"password": "admin123"
}
},
{
"name": "Kimai",
@ -2222,6 +2262,21 @@
"notes": [],
"type": "ct"
},
{
"name": "LinkStack",
"slug": "linkstack",
"desc": "LinkStack is an open-source, self-hosted alternative to Linktree, allowing users to create a customizable profile page to share multiple links, hosted on their own server.",
"script": "ct/linkstack.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/linkstack.sh",
"categories": [
9
],
"notes": [
"LinkStack can be updated via the user interface.",
"Complete setup via the web interface at http://<container-ip>/. Check installation logs: `cat ~/linkstack-install.log`"
],
"type": "ct"
},
{
"name": "Linkwarden",
"slug": "linkwarden",
@ -2384,6 +2439,18 @@
],
"type": "ct"
},
{
"name": "Mealie",
"slug": "mealie",
"desc": "Mealie is a self hosted recipe manager, meal planner and shopping list with a RestAPI backend and a reactive frontend built in Vue for a pleasant user experience for the whole family. Easily add recipes into your database by providing the URL and Mealie will automatically import the relevant data, or add a family recipe with the UI editor. Mealie also provides an API for interactions from 3rd party applications.",
"script": "ct/mealie.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/mealie.sh",
"categories": [
13
],
"notes": [],
"type": "ct"
},
{
"name": "MediaMTX",
"slug": "mediamtx",
@ -2653,7 +2720,9 @@
"categories": [
16
],
"notes": [],
"notes": [
"You may need to configure the `WEBHOOK_URL` in the config file when using a domain."
],
"type": "ct"
},
{
@ -2783,7 +2852,7 @@
}
},
{
"name": "NIC Offloading Fix",
"name": "Intel e1000e NIC Offloading Fix",
"slug": "nic-offloading-fix",
"desc": "This script automates the process of disabling network interface card (NIC) offloading features specifically for Intel e1000e network interfaces on Linux systems.",
"script": "tools/pve/nic-offloading-fix.sh",
@ -3048,7 +3117,7 @@
"script": "ct/onlyoffice.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/onlyoffice.sh",
"categories": [
9
12
],
"notes": [
"Database / RabbitMQ Credentials: `cat ~/onlyoffice.creds`"
@ -3168,23 +3237,18 @@
"type": "ct"
},
{
"name": "OPNsense",
"slug": "opnsense-vm",
"desc": "OPNsense is an open-source firewall and routing platform based on FreeBSD. It provides advanced security features, including intrusion detection, VPN support, traffic shaping, and web filtering, with an intuitive web interface for easy management. Known for its reliability and regular updates, OPNsense is a popular choice for both businesses and home networks.",
"script": "vm/opnsense-vm.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/vm/opnsense-vm.sh",
"name": "OTS",
"slug": "ots",
"desc": "One-Time-Secret sharing platform with a symmetric 256bit AES encryption in the browser.",
"script": "ct/ots.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/ots.sh",
"categories": [
4,
2
6
],
"notes": [
"It will fail with default settings if there is no vmbr0 and vmbr1 on your node. Use advanced settings in this case."
"When it is in used external please use it behind reverse proxy or create your own certificates"
],
"type": "vm",
"default_credentials": {
"username": "root",
"password": "opnsense"
}
"type": "ct"
},
{
"name": "Outline",
@ -3259,6 +3323,22 @@
"notes": [],
"type": "ct"
},
{
"name": "Palmr",
"slug": "palmr",
"desc": "Palmr is a fast and secure platform for sharing files, built with performance and privacy in mind.",
"script": "ct/palmr.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/palmr.sh",
"categories": [
11
],
"notes": [
"This LXC is very memory-hungry when updating; it requires at least 6GB RAM, but RAM may be reduced to as low as 2GB when running normally",
"To use a bind mount for storage, create symlinks to your mount for both `uploads` and `temp-uploads` in `/opt/palmr_data`",
"To use Palmr with a reverse proxy, uncomment `SECURE_SITE` in `/opt/palmr/apps/server/.env`"
],
"type": "ct"
},
{
"name": "PaperlessAI",
"slug": "paperless-ai",
@ -3849,7 +3929,7 @@
9
],
"notes": [
"Create Proxmox-API-Token first: `https://github.com/rcourtman/Pulse?tab=readme-ov-file#creating-a-proxmox-api-token`",
"Create Proxmox-API-Token first: `https://github.com/rcourtman/Pulse?tab=readme-ov-file#creating-api-token`",
"After installation, access the web interface to configure your Proxmox connection details through the built-in setup wizard"
],
"type": "ct"
@ -4057,6 +4137,18 @@
"notes": [],
"type": "ct"
},
{
"name": "Salt",
"slug": "salt",
"desc": "SaltStack Salt is a software for automating the management and configuration of IT infrastructure and applications. It is an event-driven automation tool and framework used to deploy, configure, and manage complex IT systems. Its primary functions include configuration management, where it ensures consistent configurations and manages operating system deployment and software installation. It also automates and orchestrates routine IT processes and can create self-aware, self-healing systems.",
"script": "ct/salt.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/salt.sh",
"categories": [
19
],
"notes": [],
"type": "ct"
},
{
"name": "Proxmox VE CPU Scaling Governor",
"slug": "scaling-governor",
@ -4071,18 +4163,6 @@
],
"type": "pve"
},
{
"name": "SearXNG",
"slug": "searxng",
"desc": "SearXNG is a free internet metasearch engine which aggregates results from up to 215 search services. Users are neither tracked nor profiled. Additionally, SearXNG can be used over Tor for online anonymity.",
"script": "ct/searxng.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/searxng.sh",
"categories": [
0
],
"notes": [],
"type": "ct"
},
{
"name": "seelf",
"slug": "seelf",
@ -4275,6 +4355,20 @@
"password": "null"
}
},
{
"name": "Suwayomi-Server",
"slug": "suwayomi-server",
"desc": "A free and open source manga reader server that runs extensions built for Mihon (Tachiyomi).",
"script": "ct/suwayomiserver.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/suwayomiserver.sh",
"categories": [
13
],
"notes": [
"This application can be conflicting with Kaspersky products. You maybe need to disable Kaspersky in order to use this application."
],
"type": "ct"
},
{
"name": "Syncthing",
"slug": "syncthing",
@ -4349,6 +4443,21 @@
],
"type": "ct"
},
{
"name": "Teamspeak-Server",
"slug": "teamspeak-server",
"desc": "TeamSpeak is a voice over IP (VoIP) application, primarily used by gamers and teams to chat in real time on dedicated servers. It delivers crystal\u2011clear, low\u2011latency voice communication.",
"script": "ct/teamspeak-server.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/teamspeak-server.sh",
"categories": [
24
],
"notes": [
"Use `journalctl -u teamspeak-server.service` inside Debian LXC console to check for admin credentials!",
"Use `cat /var/log/teamspeak.err.log` inside Alpine LXC console to check for admin credentials!"
],
"type": "ct"
},
{
"name": "Technitium DNS",
"slug": "technitiumdns",
@ -4470,6 +4579,21 @@
"notes": [],
"type": "ct"
},
{
"name": "Tududi",
"slug": "tududi",
"desc": "Self-hosted task management with functional programming architecture, hierarchical organization, and multi-language support.",
"script": "ct/tududi.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/tududi.sh",
"categories": [
12
],
"notes": [
"Create users like this: `cd /opt/tududi` => `npm run user:create <email> <password>`",
"Database location: `/opt/tududi-db`. Uploads: `/opt/tududi-uploads`"
],
"type": "ct"
},
{
"name": "TurnKey",
"slug": "turnkey",
@ -4539,20 +4663,6 @@
],
"type": "vm"
},
{
"name": "Ubuntu 24.10",
"slug": "ubuntu2410-vm",
"desc": "Ubuntu is a distribution based on Debian, designed to have regular releases and a consistent user experience.",
"script": "vm/ubuntu2410-vm.sh",
"script_url": "https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/vm/ubuntu2410-vm.sh",
"categories": [
2
],
"notes": [
"after installation, checkout: \u00b4https://github.com/community-scripts/ProxmoxVE/discussions/272\u00b4"
],
"type": "vm"
},
{
"name": "Ubuntu 25.04",
"slug": "ubuntu2504-vm",
@ -4733,7 +4843,9 @@
"categories": [
8
],
"notes": [],
"notes": [
"Included option to install VictoriaLogs."
],
"type": "ct"
},
{

View File

@ -31,7 +31,7 @@ if [[ -f "$UTILS_FILE" ]]; then
fi
load_language
initialize_cache
show_proxmenux_logo
# ==========================================================

View File

@ -0,0 +1,335 @@
#!/bin/bash
# ==========================================================
# Common Functions for Proxmox VE Scripts
# ==========================================================
# Configuration
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
VENV_PATH="/opt/googletrans-env"
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
if [[ -f "$UTILS_FILE" ]]; then
source "$UTILS_FILE"
fi
load_language
initialize_cache
get_pve_info() {
local pve_full_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
local pve_major=$(echo "$pve_full_version" | cut -d. -f1)
local os_codename="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs)"
if [ -z "$os_codename" ]; then
os_codename=$(lsb_release -cs 2>/dev/null)
fi
local target_codename
if [ "$pve_major" -ge 9 ] 2>/dev/null; then
target_codename="trixie"
else
target_codename="$os_codename"
if [ -z "$target_codename" ]; then
target_codename="bookworm"
fi
fi
echo "$pve_full_version|$pve_major|$os_codename|$target_codename"
}
lvm_repair_check() {
msg_info "$(translate "Checking and repairing old LVM PV headers (if needed)...")"
if ! command -v pvs >/dev/null 2>&1; then
msg_info "$(translate "LVM tools not available, skipping LVM check")"
return
fi
pvs_output=$(LC_ALL=C pvs -v 2>&1 | grep "old PV header" || true)
if [ -z "$pvs_output" ]; then
msg_ok "$(translate "No PVs with old headers found.")"
return
fi
declare -A vg_map
while read -r line; do
pv=$(echo "$line" | grep -o '/dev/[^ ]*' || true)
if [ -n "$pv" ]; then
vg=$(pvs -o vg_name --noheadings "$pv" 2>/dev/null | awk '{print $1}' || true)
if [ -n "$vg" ]; then
vg_map["$vg"]=1
fi
fi
done <<< "$pvs_output"
for vg in "${!vg_map[@]}"; do
msg_warn "$(translate "Old PV header(s) found in VG $vg. Updating metadata...")"
vgck --updatemetadata "$vg" 2>/dev/null
vgchange -ay "$vg" 2>/dev/null
if [ $? -ne 0 ]; then
msg_warn "$(translate "Metadata update failed for VG $vg. Review manually.")"
else
msg_ok "$(translate "Metadata updated successfully for VG $vg")"
fi
done
msg_ok "$(translate "LVM PV headers check completed")"
}
cleanup_duplicate_repos_pve9() {
msg_info "$(translate "Cleaning up duplicate repositories...")"
local sources_file="/etc/apt/sources.list"
local temp_file=$(mktemp)
local cleaned_count=0
declare -A seen_repos
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "$line" ]]; then
echo "$line" >> "$temp_file"
continue
fi
if [[ "$line" =~ ^deb ]]; then
read -r _ url dist components <<< "$line"
local key="${url}_${dist}"
if [[ -v "seen_repos[$key]" ]]; then
echo "# $line" >> "$temp_file"
cleaned_count=$((cleaned_count + 1))
msg_info "$(translate "Commented duplicate: $url $dist")"
else
echo "$line" >> "$temp_file"
seen_repos[$key]="$components"
fi
else
echo "$line" >> "$temp_file"
fi
done < "$sources_file"
mv "$temp_file" "$sources_file"
chmod 644 "$sources_file"
if [ -f "/etc/apt/sources.list.d/proxmox.sources" ]; then
if grep -q "^deb.*download\.proxmox\.com" "$sources_file"; then
sed -i '/^deb.*download\.proxmox\.com/s/^/# /' "$sources_file"
cleaned_count=$((cleaned_count + 1))
fi
for list_file in /etc/apt/sources.list.d/pve-*.list; do
if [ -f "$list_file" ] && [[ "$list_file" != "/etc/apt/sources.list.d/pve-enterprise.list" ]]; then
if grep -q "^deb" "$list_file"; then
sed -i 's/^deb/# deb/g' "$list_file"
cleaned_count=$((cleaned_count + 1))
fi
fi
done
if [ -f "/etc/apt/sources.list.d/debian.sources" ]; then
if grep -q "^deb.*deb\.debian\.org" "$sources_file"; then
sed -i '/^deb.*deb\.debian\.org/s/^/# /' "$sources_file"
cleaned_count=$((cleaned_count + 1))
fi
if grep -q "^deb.*security\.debian\.org" "$sources_file"; then
sed -i '/^deb.*security\.debian\.org/s/^/# /' "$sources_file"
cleaned_count=$((cleaned_count + 1))
fi
fi
fi
if [ -f "/etc/apt/sources.list.d/proxmox.sources" ]; then
for old_file in /etc/apt/sources.list.d/pve-public-repo.list /etc/apt/sources.list.d/pve-install-repo.list; do
if [ -f "$old_file" ]; then
rm -f "$old_file"
cleaned_count=$((cleaned_count + 1))
fi
done
fi
if [ $cleaned_count -gt 0 ]; then
msg_ok "$(translate "Cleaned up $cleaned_count duplicate/old repositories")"
apt-get update > /dev/null 2>&1 || true
else
msg_ok "$(translate "No duplicate repositories found")"
fi
}
cleanup_duplicate_repos_pve9_() {
msg_info "$(translate "Cleaning up duplicate repositories...")"
local sources_file="/etc/apt/sources.list"
local temp_file=$(mktemp)
local cleaned_count=0
declare -A seen_repos
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "$line" ]]; then
echo "$line" >> "$temp_file"
continue
fi
if [[ "$line" =~ ^deb ]]; then
read -r _ url dist components <<< "$line"
local key="${url}_${dist}"
if [[ -v "seen_repos[$key]" ]]; then
echo "# $line" >> "$temp_file"
cleaned_count=$((cleaned_count + 1))
else
echo "$line" >> "$temp_file"
seen_repos[$key]="$components"
fi
else
echo "$line" >> "$temp_file"
fi
done < "$sources_file"
mv "$temp_file" "$sources_file"
chmod 644 "$sources_file"
for src in proxmox debian ceph; do
local sources_path="/etc/apt/sources.list.d/${src}.sources"
if [ -f "$sources_path" ]; then
case "$src" in
proxmox)
url_match="download.proxmox.com"
;;
debian)
url_match="deb.debian.org"
;;
ceph)
url_match="download.proxmox.com/ceph"
;;
*)
url_match=""
;;
esac
if [[ -n "$url_match" ]]; then
if grep -q "^deb.*$url_match" "$sources_file"; then
sed -i "/^deb.*$url_match/s/^/# /" "$sources_file"
cleaned_count=$((cleaned_count + 1))
fi
fi
for list_file in /etc/apt/sources.list.d/*.list; do
[[ -f "$list_file" ]] || continue
if grep -q "^deb.*$url_match" "$list_file"; then
sed -i "/^deb.*$url_match/s/^/# /" "$list_file"
cleaned_count=$((cleaned_count + 1))
fi
done
fi
done
if [ $cleaned_count -gt 0 ]; then
msg_ok "$(translate "Cleaned up $cleaned_count duplicate/old repositories")"
apt-get update > /dev/null 2>&1 || true
else
msg_ok "$(translate "No duplicate repositories found")"
fi
}
cleanup_duplicate_repos_pve8() {
msg_info "$(translate "Cleaning up duplicate repositories...")"
local cleaned_count=0
local sources_file="/etc/apt/sources.list"
if [[ -f "$sources_file" ]]; then
local temp_file
temp_file=$(mktemp)
declare -A seen_repos
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "$line" ]]; then
echo "$line" >> "$temp_file"
continue
fi
if [[ "$line" =~ ^[[:space:]]*deb ]]; then
read -r _ url dist components <<< "$line"
local key="${url}_${dist}"
if [[ -v "seen_repos[$key]" ]]; then
echo "# $line" >> "$temp_file"
cleaned_count=$((cleaned_count + 1))
else
echo "$line" >> "$temp_file"
seen_repos[$key]="$components"
fi
else
echo "$line" >> "$temp_file"
fi
done < "$sources_file"
mv "$temp_file" "$sources_file"
chmod 644 "$sources_file"
fi
local old_pve_files=(/etc/apt/sources.list.d/pve-*.list /etc/apt/sources.list.d/proxmox.list)
for file in "${old_pve_files[@]}"; do
if [[ -f "$file" ]]; then
local base_name
base_name=$(basename "$file" .list)
local sources_equiv="/etc/apt/sources.list.d/${base_name}.sources"
if [[ -f "$sources_equiv" ]] && grep -q "^Enabled: *true" "$sources_equiv"; then
msg_info "$(translate "Removing old repository file: $(basename "$file")")"
rm -f "$file"
cleaned_count=$((cleaned_count + 1))
fi
fi
done
if [ "$cleaned_count" -gt 0 ]; then
msg_ok "$(translate "Cleaned up $cleaned_count duplicate/old repositories")"
apt-get update > /dev/null 2>&1 || true
else
msg_ok "$(translate "No duplicate repositories found")"
fi
}
cleanup_duplicate_repos() {
local pve_version
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
if [[ -z "$pve_version" ]]; then
msg_error "Unable to detect Proxmox version."
return 1
fi
if [[ "$pve_version" -ge 9 ]]; then
cleanup_duplicate_repos_pve9
else
cleanup_duplicate_repos_pve8
fi
}

View File

@ -0,0 +1,76 @@
#!/bin/bash
# ==========================================================
# Remove Subscription Banner - Proxmox VE 8.4.9
# ==========================================================
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
VENV_PATH="/opt/googletrans-env"
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
if [[ -f "$UTILS_FILE" ]]; then
source "$UTILS_FILE"
fi
load_language
initialize_cache
ensure_tools_json() {
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
}
register_tool() {
local tool="$1"
local state="$2"
ensure_tools_json
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
}
remove_subscription_banner_pve8() {
local JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
local GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
local APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
local BACKUP_FILE="${JS_FILE}.bak.$(date +%F_%T)"
local pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+' | head -1)
local pve_major=$(echo "$pve_version" | cut -d. -f1)
if [[ "$pve_major" -ne 8 ]]; then
msg_error "This script is only for Proxmox VE 8.x. Detected: $pve_version"
return 1
fi
msg_info "Detected Proxmox VE $pve_version - Applying safe JS patch..."
if [[ ! -f "$JS_FILE" ]]; then
msg_error "JavaScript file not found: $JS_FILE"
return 1
fi
cp "$JS_FILE" "$BACKUP_FILE"
sed -i "s/No valid subscription/Subscription active/g" "$JS_FILE"
sed -i "s/Ext.Msg.WARNING/Ext.Msg.INFO/g" "$JS_FILE"
sed -i "s/res.data.status.toLowerCase() !== 'active'/false/g" "$JS_FILE"
sed -i "s/subscriptionActive: ''/subscriptionActive: true/g" "$JS_FILE"
[[ -f "$GZ_FILE" ]] && rm -f "$GZ_FILE"
find /var/cache/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
find /var/lib/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
[[ -f "$APT_HOOK" ]] && rm -f "$APT_HOOK"
msg_ok "Subscription banner removed successfully."
register_tool "subscription_banner" true
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
remove_subscription_banner_pve8
fi

View File

@ -0,0 +1,119 @@
#!/bin/bash
# ==========================================================
# Remove Subscription Banner - Proxmox VE 9.x ONLY
# ==========================================================
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
VENV_PATH="/opt/googletrans-env"
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
if [[ -f "$UTILS_FILE" ]]; then
source "$UTILS_FILE"
fi
load_language
initialize_cache
# Tool registration system
ensure_tools_json() {
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
}
register_tool() {
local tool="$1"
local state="$2"
ensure_tools_json
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
}
remove_subscription_banner_pve9() {
local JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
local MIN_JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js"
local GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
local APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
# Verify PVE 9.x
local pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+' | head -1)
local pve_major=$(echo "$pve_version" | cut -d. -f1)
if [ "$pve_major" -lt 9 ] 2>/dev/null; then
msg_error "This script is for PVE 9.x only. Detected PVE $pve_version"
return 1
fi
msg_info "Detected Proxmox VE $pve_version - Applying PVE 9.x patches"
# Verify that the file exists
if [ ! -f "$JS_FILE" ]; then
msg_error "JavaScript file not found: $JS_FILE"
return 1
fi
# Create backup of original file
local backup_file="${JS_FILE}.backup.pve9.$(date +%Y%m%d_%H%M%S)"
cp "$JS_FILE" "$backup_file"
# Clean any existing problematic APT hooks
for f in /etc/apt/apt.conf.d/*nag*; do
[[ -e "$f" ]] && rm -f "$f"
done
# Main subscription check patches for PVE 9
sed -i "s/res\.data\.status\.toLowerCase() !== 'active'/false/g" "$JS_FILE"
sed -i "s/subscriptionActive: ''/subscriptionActive: true/g" "$JS_FILE"
sed -i "s/title: gettext('No valid subscription')/title: gettext('Community Edition')/g" "$JS_FILE"
# Additional UX improvements for PVE 9
sed -i "s/You do not have a valid subscription for this server/Community Edition - No subscription required/g" "$JS_FILE"
sed -i "s/Enterprise repository needs valid subscription/Enterprise repository configured/g" "$JS_FILE"
sed -i "s/icon: Ext\.Msg\.WARNING/icon: Ext.Msg.INFO/g" "$JS_FILE"
# Additional subscription patterns that may exist in PVE 9
sed -i "s/subscription = !(/subscription = false \&\& (/g" "$JS_FILE"
# Remove compressed/minified files to force regeneration
[[ -f "$GZ_FILE" ]] && rm -f "$GZ_FILE"
[[ -f "$MIN_JS_FILE" ]] && rm -f "$MIN_JS_FILE"
# Clear various caches
find /var/cache/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
find /var/lib/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
# Create PVE 9.x specific APT hook
[[ -f "$APT_HOOK" ]] && rm -f "$APT_HOOK"
cat > "$APT_HOOK" << 'EOF'
DPkg::Post-Invoke {
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/res\\.data\\.status\\.toLowerCase() !== '\''active'\''/false/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/subscriptionActive: '\'\'\''/subscriptionActive: true/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/title: gettext('\''No valid subscription'\'')/title: gettext('\''Community Edition'\'')/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/subscription = !(/subscription = false \\&\\& (/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
"rm -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz || true";
};
EOF
chmod 644 "$APT_HOOK"
# Verify APT hook syntax
if ! apt-config dump >/dev/null 2>&1; then
msg_warn "APT hook has syntax issues, removing..."
rm -f "$APT_HOOK"
else
msg_ok "APT hook created successfully"
fi
msg_ok "Subscription banner removed successfully for Proxmox VE $pve_version"
msg_ok "Banner removal process completed"
register_tool "subscription_banner" true
}
# Execute function if called directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
remove_subscription_banner_pve9
fi

View File

@ -0,0 +1,337 @@
#!/bin/bash
# ==========================================================
# Proxmox VE Update Script
# ==========================================================
# Configuration
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
VENV_PATH="/opt/googletrans-env"
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
if [[ -f "$UTILS_FILE" ]]; then
source "$UTILS_FILE"
fi
load_language
initialize_cache
ensure_tools_json() {
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
}
register_tool() {
local tool="$1"
local state="$2"
ensure_tools_json
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
}
download_common_functions() {
if ! source <(curl -s "$REPO_URL/scripts/global/common-functions.sh"); then
return 1
fi
}
update_pve9() {
local start_time=$(date +%s)
local log_file="/var/log/proxmox-update-$(date +%Y%m%d-%H%M%S).log"
local changes_made=false
local OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs)"
local TARGET_CODENAME="trixie"
if [ -z "$OS_CODENAME" ]; then
OS_CODENAME=$(lsb_release -cs 2>/dev/null || echo "trixie")
fi
download_common_functions
msg_info2 "$(translate "Detected: Proxmox VE 9.x (Current: $OS_CODENAME, Target: $TARGET_CODENAME)")"
echo
local available_space=$(df /var/cache/apt/archives | awk 'NR==2 {print int($4/1024)}')
if [ "$available_space" -lt 1024 ]; then
msg_error "$(translate "Insufficient disk space. Available: ${available_space}MB")"
echo -e
msg_success "$(translate "Press Enter to return to menu...")"
read -r
return 1
fi
if ! ping -c 1 download.proxmox.com >/dev/null 2>&1; then
msg_error "$(translate "Cannot reach Proxmox repositories")"
echo -e
msg_success "$(translate "Press Enter to return to menu...")"
read -r
return 1
fi
disable_sources_repo() {
local file="$1"
if [[ -f "$file" ]]; then
sed -i ':a;/^\n*$/{$d;N;ba}' "$file"
if grep -q "^Enabled:" "$file"; then
sed -i 's/^Enabled:.*$/Enabled: false/' "$file"
else
echo "Enabled: false" >> "$file"
fi
if ! grep -q "^Types: " "$file"; then
msg_warn "$(translate "Malformed .sources file detected, removing: $(basename "$file")")"
rm -f "$file"
fi
return 0
fi
return 1
}
if disable_sources_repo "/etc/apt/sources.list.d/pve-enterprise.sources"; then
msg_ok "$(translate "Enterprise Proxmox repository disabled")"
changes_made=true
fi
if disable_sources_repo "/etc/apt/sources.list.d/ceph.sources"; then
msg_ok "$(translate "Enterprise Proxmox Ceph repository disabled")"
changes_made=true
fi
for legacy_file in /etc/apt/sources.list.d/pve-public-repo.list \
/etc/apt/sources.list.d/pve-install-repo.list \
/etc/apt/sources.list.d/debian.list; do
if [[ -f "$legacy_file" ]]; then
rm -f "$legacy_file"
msg_ok "$(translate "Removed legacy repository: $(basename "$legacy_file")")"
fi
done
if [[ -f /etc/apt/sources.list.d/debian.sources ]]; then
rm -f /etc/apt/sources.list.d/debian.sources
msg_ok "$(translate "Old debian.sources file removed to prevent duplication")"
fi
msg_info "$(translate "Creating Proxmox VE 9.x no-subscription repository...")"
cat > /etc/apt/sources.list.d/proxmox.sources << EOF
Enabled: true
Types: deb
URIs: http://download.proxmox.com/debian/pve
Suites: ${TARGET_CODENAME}
Components: pve-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF
msg_ok "$(translate "Proxmox VE 9.x no-subscription repository created")"
changes_made=true
msg_info "$(translate "Creating Debian ${TARGET_CODENAME} sources file...")"
cat > /etc/apt/sources.list.d/debian.sources << EOF
Types: deb
URIs: http://deb.debian.org/debian/
Suites: ${TARGET_CODENAME} ${TARGET_CODENAME}-updates
Components: main contrib non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
URIs: http://security.debian.org/debian-security/
Suites: ${TARGET_CODENAME}-security
Components: main contrib non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
EOF
msg_ok "$(translate "Debian repositories configured for $TARGET_CODENAME")"
local firmware_conf="/etc/apt/apt.conf.d/no-firmware-warnings.conf"
if [ ! -f "$firmware_conf" ]; then
msg_info "$(translate "Disabling non-free firmware warnings...")"
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' > "$firmware_conf"
msg_ok "$(translate "Non-free firmware warnings disabled")"
fi
cleanup_duplicate_repos
update_output=$(apt-get update 2>&1)
update_exit_code=$?
if [ $update_exit_code -eq 0 ]; then
msg_ok "$(translate "Package lists updated successfully")"
else
if echo "$update_output" | grep -q "NO_PUBKEY\|GPG error"; then
msg_info "$(translate "Fixing GPG key issues...")"
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys $(echo "$update_output" | grep "NO_PUBKEY" | sed 's/.*NO_PUBKEY //' | head -1) 2>/dev/null
if apt-get update > "$log_file" 2>&1; then
msg_ok "$(translate "Package lists updated after GPG fix")"
else
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
return 1
fi
elif echo "$update_output" | grep -q "404\|Failed to fetch"; then
msg_warn "$(translate "Some repositories are not available, continuing with available ones...")"
else
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
echo "Error details: $update_output"
return 1
fi
fi
if apt policy 2>/dev/null | grep -q "${TARGET_CODENAME}.*pve-no-subscription"; then
msg_ok "$(translate "Proxmox VE 9.x repositories verified")"
else
msg_warn "$(translate "Proxmox VE 9.x repositories verification inconclusive, continuing...")"
fi
local current_pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
local available_pve_version=$(apt-cache policy pve-manager 2>/dev/null | grep -oP 'Candidate: \K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
local upgradable=$(apt list --upgradable 2>/dev/null | grep -c "upgradable")
local security_updates=$(apt list --upgradable 2>/dev/null | grep -c "security")
show_update_menu() {
local current_version="$1"
local target_version="$2"
local upgradable_count="$3"
local security_count="$4"
local menu_text="$(translate "System Update Information")\n\n"
menu_text+="$(translate "Current PVE Version"): $current_version\n"
if [ -n "$target_version" ] && [ "$target_version" != "$current_version" ]; then
menu_text+="$(translate "Available PVE Version"): $target_version\n"
fi
menu_text+="\n$(translate "Package Updates Available"): $upgradable_count\n"
menu_text+="$(translate "Security Updates"): $security_count\n\n"
if [ "$upgradable_count" -eq 0 ]; then
menu_text+="$(translate "System is already up to date")"
whiptail --title "$(translate "Update Status")" --msgbox "$menu_text" 15 70
return 2
else
menu_text+="$(translate "Do you want to proceed with the system update?")"
if whiptail --title "$(translate "Proxmox Update")" --yesno "$menu_text" 18 70; then
return 0
else
return 1
fi
fi
}
show_update_menu "$current_pve_version" "$available_pve_version" "$upgradable" "$security_updates"
MENU_RESULT=$?
if [[ $MENU_RESULT -eq 1 ]]; then
msg_info2 "$(translate "Update cancelled by user")"
apt-get -y autoremove > /dev/null 2>&1 || true
apt-get -y autoclean > /dev/null 2>&1 || true
return 0
elif [[ $MENU_RESULT -eq 2 ]]; then
msg_ok "$(translate "System is already up to date. No update needed.")"
apt-get -y autoremove > /dev/null 2>&1 || true
apt-get -y autoclean > /dev/null 2>&1 || true
return 0
fi
msg_info "$(translate "Removing conflicting utilities...")"
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' purge ntp openntpd systemd-timesyncd > /dev/null 2>&1; then
msg_ok "$(translate "Conflicting utilities removed")"
else
msg_warn "$(translate "Some conflicting utilities may not have been removed")"
fi
msg_info "$(translate "Updating packages...")"
apt-get install pv -y > /dev/null 2>&1
msg_ok "$(translate "Packages updated successfully")"
tput sc
DEBIAN_FRONTEND=noninteractive apt-get -y \
-o Dpkg::Options::='--force-confdef' \
-o Dpkg::Options::='--force-confold' \
dist-upgrade 2>&1 | while IFS= read -r line; do
echo "$line" >> "$log_file"
if [[ "$line" =~ \[[#=\-]+\]\ *[0-9]{1,3}% ]]; then
continue
fi
if [[ "$line" =~ ^(Setting\ up|Unpacking|Preparing\ to\ unpack|Processing\ triggers\ for) ]]; then
package_name=$(echo "$line" | sed -E 's/.*(Setting up|Unpacking|Preparing to unpack|Processing triggers for) ([^ :]+).*/\2/')
[ -z "$package_name" ] && package_name="$(translate "Unknown")"
row=$(( $(tput lines) - 6 ))
tput cup $row 0; printf "%s\n" "$(translate "Installing packages...")"
tput cup $((row + 1)) 0; printf "%s\n" "──────────────────────────────────────────────"
tput cup $((row + 2)) 0; printf "%s %s\n" "$(translate "Package:")" "$package_name"
tput cup $((row + 3)) 0; printf "%s\n" "Progress: [ ] 0%"
tput cup $((row + 4)) 0; printf "%s\n" "──────────────────────────────────────────────"
for i in $(seq 1 10); do
sleep 0.1
progress=$((i * 10))
tput cup $((row + 3)) 9
printf "[%-50s] %3d%%" "$(printf "#%.0s" $(seq 1 $((progress/2))))" "$progress"
done
fi
done
tput rc
tput ed
upgrade_exit_code=${PIPESTATUS[0]}
if [ $upgrade_exit_code -eq 0 ]; then
msg_ok "$(translate "System upgrade completed successfully")"
else
msg_error "$(translate "System upgrade failed. Check log: $log_file")"
return 1
fi
msg_info "$(translate "Installing essential Proxmox packages...")"
local additional_packages="zfsutils-linux proxmox-backup-restore-image chrony"
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' install $additional_packages >> "$log_file" 2>&1; then
msg_ok "$(translate "Essential Proxmox packages installed")"
else
msg_warn "$(translate "Some essential Proxmox packages may not have been installed")"
fi
lvm_repair_check
cleanup_duplicate_repos
msg_info "$(translate "Performing system cleanup...")"
apt-get -y autoremove > /dev/null 2>&1 || true
apt-get -y autoclean > /dev/null 2>&1 || true
msg_ok "$(translate "Cleanup finished")"
local end_time=$(date +%s)
local duration=$((end_time - start_time))
local minutes=$((duration / 60))
local seconds=$((duration % 60))
echo -e "${TAB}${BGN}$(translate "====== PVE UPDATE COMPLETED ======")${CL}"
echo -e "${TAB}${GN}⏱️ $(translate "Duration")${CL}: ${BL}${minutes}m ${seconds}s${CL}"
echo -e "${TAB}${GN}📄 $(translate "Log file")${CL}: ${BL}$log_file${CL}"
echo -e "${TAB}${GN}📦 $(translate "Packages upgraded")${CL}: ${BL}$upgradable${CL}"
echo -e "${TAB}${GN}🖥️ $(translate "Proxmox VE")${CL}: ${BL}$target_version (Debian $OS_CODENAME)${CL}"
msg_ok "$(translate "Proxmox VE 9.x configuration completed.")"
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
update_pve9
fi

View File

@ -0,0 +1,284 @@
#!/bin/bash
# ==========================================================
# Proxmox VE 8.x Update Script
# ==========================================================
# Configuration
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
VENV_PATH="/opt/googletrans-env"
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
if [[ -f "$UTILS_FILE" ]]; then
source "$UTILS_FILE"
fi
load_language
initialize_cache
ensure_tools_json() {
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
}
register_tool() {
local tool="$1"
local state="$2"
ensure_tools_json
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
}
download_common_functions() {
if ! source <(curl -s "$REPO_URL/scripts/global/common-functions.sh"); then
return 1
fi
}
update_pve8() {
local start_time=$(date +%s)
local log_file="/var/log/proxmox-update-$(date +%Y%m%d-%H%M%S).log"
local changes_made=false
local OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs)"
if [ -z "$OS_CODENAME" ]; then
OS_CODENAME=$(lsb_release -cs 2>/dev/null || echo "bookworm")
fi
download_common_functions
msg_info2 "$(translate "Detected: Proxmox VE 8.x (Debian $OS_CODENAME)")"
echo
local available_space=$(df /var/cache/apt/archives | awk 'NR==2 {print int($4/1024)}')
if [ "$available_space" -lt 1024 ]; then
msg_error "$(translate "Insufficient disk space. Available: ${available_space}MB")"
echo -e
msg_success "$(translate "Press Enter to return to menu...")"
read -r
return 1
fi
if ! ping -c 1 download.proxmox.com >/dev/null 2>&1; then
msg_error "$(translate "Cannot reach Proxmox repositories")"
echo -e
msg_success "$(translate "Press Enter to return to menu...")"
read -r
return 1
fi
if [ -f /etc/apt/sources.list.d/pve-enterprise.list ] && grep -q "^deb" /etc/apt/sources.list.d/pve-enterprise.list; then
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/pve-enterprise.list
msg_ok "$(translate "Enterprise Proxmox repository disabled")"
changes_made=true
fi
if [ -f /etc/apt/sources.list.d/ceph.list ] && grep -q "^deb" /etc/apt/sources.list.d/ceph.list; then
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/ceph.list
msg_ok "$(translate "Enterprise Proxmox Ceph repository disabled")"
changes_made=true
fi
if [ ! -f /etc/apt/sources.list.d/pve-public-repo.list ] || ! grep -q "pve-no-subscription" /etc/apt/sources.list.d/pve-public-repo.list; then
echo "deb http://download.proxmox.com/debian/pve $OS_CODENAME pve-no-subscription" > /etc/apt/sources.list.d/pve-public-repo.list
msg_ok "$(translate "Free public Proxmox repository enabled")"
changes_made=true
fi
local sources_file="/etc/apt/sources.list"
cp "$sources_file" "${sources_file}.backup.$(date +%Y%m%d_%H%M%S)"
if grep -q -E "(debian-security -security|debian main$|debian -updates)" "$sources_file"; then
sed -i '/^deb.*debian-security -security/d' "$sources_file"
sed -i '/^deb.*debian main$/d' "$sources_file"
sed -i '/^deb.*debian -updates/d' "$sources_file"
changes_made=true
msg_ok "$(translate "Malformed repository entries cleaned")"
fi
cat > "$sources_file" << EOF
# Debian $OS_CODENAME repositories
deb http://deb.debian.org/debian $OS_CODENAME main contrib non-free non-free-firmware
deb http://deb.debian.org/debian $OS_CODENAME-updates main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security $OS_CODENAME-security main contrib non-free non-free-firmware
EOF
msg_ok "$(translate "Debian repositories configured for $OS_CODENAME")"
local firmware_conf="/etc/apt/apt.conf.d/no-firmware-warnings.conf"
if [ ! -f "$firmware_conf" ]; then
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' > "$firmware_conf"
fi
cleanup_duplicate_repos
msg_info "$(translate "Updating package lists...")"
if apt-get update > "$log_file" 2>&1; then
msg_ok "$(translate "Package lists updated successfully")"
else
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
return 1
fi
local current_pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
local available_pve_version=$(apt-cache policy pve-manager 2>/dev/null | grep -oP 'Candidate: \K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
local upgradable=$(apt list --upgradable 2>/dev/null | grep -c "upgradable")
local security_updates=$(apt list --upgradable 2>/dev/null | grep -c "security")
show_update_menu() {
local current_version="$1"
local target_version="$2"
local upgradable_count="$3"
local security_count="$4"
local menu_text="$(translate "System Update Information")\n\n"
menu_text+="$(translate "Current PVE Version"): $current_version\n"
if [ -n "$target_version" ] && [ "$target_version" != "$current_version" ]; then
menu_text+="$(translate "Available PVE Version"): $target_version\n"
fi
menu_text+="\n$(translate "Package Updates Available"): $upgradable_count\n"
menu_text+="$(translate "Security Updates"): $security_count\n\n"
if [ "$upgradable_count" -eq 0 ]; then
menu_text+="$(translate "System is already up to date")"
whiptail --title "$(translate "Update Status")" --msgbox "$menu_text" 15 70
return 2
else
menu_text+="$(translate "Do you want to proceed with the system update?")"
if whiptail --title "$(translate "Proxmox Update")" --yesno "$menu_text" 18 70; then
return 0
else
return 1
fi
fi
}
show_update_menu "$current_pve_version" "$available_pve_version" "$upgradable" "$security_updates"
MENU_RESULT=$?
if [[ $MENU_RESULT -eq 1 ]]; then
msg_info2 "$(translate "Update cancelled by user")"
apt-get -y autoremove > /dev/null 2>&1 || true
apt-get -y autoclean > /dev/null 2>&1 || true
return 0
elif [[ $MENU_RESULT -eq 2 ]]; then
msg_ok "$(translate "System is already up to date. No update needed.")"
apt-get -y autoremove > /dev/null 2>&1 || true
apt-get -y autoclean > /dev/null 2>&1 || true
return 0
fi
local conflicting_packages=$(dpkg -l 2>/dev/null | grep -E "^ii.*(ntp|openntpd|systemd-timesyncd)" | awk '{print $2}')
if [ -n "$conflicting_packages" ]; then
msg_info "$(translate "Removing conflicting utilities...")"
DEBIAN_FRONTEND=noninteractive apt-get -y purge $conflicting_packages >> "$log_file" 2>&1
msg_ok "$(translate "Conflicting utilities removed")"
fi
export DEBIAN_FRONTEND=noninteractive
export APT_LISTCHANGES_FRONTEND=none
export NEEDRESTART_MODE=a
export UCF_FORCE_CONFOLD=1
export DPKG_OPTIONS="--force-confdef --force-confold"
msg_info "$(translate "Performing packages upgrade...")"
apt-get install pv -y > /dev/null 2>&1
total_packages=$(apt-get -s dist-upgrade | grep "^Inst" | wc -l)
msg_ok "$(translate "Packages upgrade successfull")"
if [ "$total_packages" -eq 0 ]; then
total_packages=1
fi
tput civis
tput sc
(
/usr/bin/env \
DEBIAN_FRONTEND=noninteractive \
APT_LISTCHANGES_FRONTEND=none \
NEEDRESTART_MODE=a \
UCF_FORCE_CONFOLD=1 \
apt-get -y \
-o Dpkg::Options::="--force-confdef" \
-o Dpkg::Options::="--force-confold" \
dist-upgrade 2>&1 | \
while IFS= read -r line; do
if [[ "$line" =~ ^(Setting\ up|Unpacking|Preparing\ to\ unpack|Processing\ triggers\ for) ]]; then
package_name=$(echo "$line" | sed -E 's/.*(Setting up|Unpacking|Preparing to unpack|Processing triggers for) ([^ ]+).*/\2/')
[ -z "$package_name" ] && package_name="$(translate "Unknown")"
tput rc
tput ed
row=$(( $(tput lines) - 6 ))
tput cup $row 0; echo "$(translate "Installing packages...")"
tput cup $((row + 1)) 0; echo "──────────────────────────────────────────────"
tput cup $((row + 2)) 0; echo "Package: $package_name"
tput cup $((row + 3)) 0; echo "Progress: [ ] 0%"
tput cup $((row + 4)) 0; echo "──────────────────────────────────────────────"
for i in $(seq 1 10); do
progress=$((i * 10))
tput cup $((row + 3)) 9
printf "[%-50s] %3d%%" "$(printf "#%.0s" $(seq 1 $((progress/2))))" "$progress"
done
fi
done
)
if [ $? -eq 0 ]; then
tput rc
tput ed
tput cnorm
msg_ok "$(translate "System upgrade completed")"
fi
local essential_packages=("zfsutils-linux" "proxmox-backup-restore-image" "chrony")
local missing_packages=()
for package in "${essential_packages[@]}"; do
if ! dpkg -l 2>/dev/null | grep -q "^ii $package "; then
missing_packages+=("$package")
fi
done
if [ ${#missing_packages[@]} -gt 0 ]; then
msg_info "$(translate "Installing essential Proxmox packages...")"
DEBIAN_FRONTEND=noninteractive apt-get -y install "${missing_packages[@]}" >> "$log_file" 2>&1
msg_ok "$(translate "Essential Proxmox packages installed")"
fi
lvm_repair_check
cleanup_duplicate_repos
msg_info "$(translate "Performing system cleanup...")"
apt-get -y autoremove > /dev/null 2>&1 || true
apt-get -y autoclean > /dev/null 2>&1 || true
msg_ok "$(translate "Cleanup finished")"
local end_time=$(date +%s)
local duration=$((end_time - start_time))
local minutes=$((duration / 60))
local seconds=$((duration % 60))
echo -e "${TAB}${BGN}$(translate "====== PVE UPDATE COMPLETED ======")${CL}"
echo -e "${TAB}${GN}⏱️ $(translate "Duration")${CL}: ${BL}${minutes}m ${seconds}s${CL}"
echo -e "${TAB}${GN}📄 $(translate "Log file")${CL}: ${BL}$log_file${CL}"
echo -e "${TAB}${GN}📦 $(translate "Packages upgraded")${CL}: ${BL}$upgradable${CL}"
echo -e "${TAB}${GN}🖥️ $(translate "Proxmox VE")${CL}: ${BL}$target_version (Debian $OS_CODENAME)${CL}"
msg_ok "$(translate "Proxmox VE 8 system update completed successfully")"
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
update_pve8
fi

View File

@ -72,8 +72,8 @@ validate_container_id() {
fi
}
# Añadir regla udev para Coral USB para persistencia de permisos
add_udev_rule_for_coral_usb() {
add_udev_rule_for_coral_usb_() {
RULE_FILE="/etc/udev/rules.d/99-coral-usb.rules"
RULE_CONTENT='SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="9302", MODE="0666", TAG+="uaccess"'
@ -87,6 +87,22 @@ add_udev_rule_for_coral_usb() {
}
add_udev_rule_for_coral_usb() {
RULE_FILE="/etc/udev/rules.d/99-coral-usb.rules"
RULE_CONTENT='# Coral USB Accelerator
SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="9302", MODE="0666", TAG+="uaccess", SYMLINK+="coral"
# Coral Dev Board / Mini PCIe
SUBSYSTEM=="usb", ATTRS{idVendor}=="1a6e", ATTRS{idProduct}=="089a", MODE="0666", TAG+="uaccess", SYMLINK+="coral"'
if [[ ! -f "$RULE_FILE" ]] || ! grep -q "18d1.*9302\|1a6e.*089a" "$RULE_FILE"; then
echo "$RULE_CONTENT" > "$RULE_FILE"
udevadm control --reload-rules && udevadm trigger
msg_ok "$(translate 'Udev rules for Coral USB devices added and rules reloaded.')"
else
msg_ok "$(translate 'Udev rules for Coral USB devices already exist.')"
fi
}
add_mount_if_needed() {
local DEVICE="$1"

135
scripts/lcx/jd2.sh Normal file
View File

@ -0,0 +1,135 @@
#!/bin/bash
# Script para instalar JDownloader en un contenedor LXC desde el host Proxmox
# Autor: MacRimi
# Mostrar lista de CTs
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
if [ -z "$CT_LIST" ]; then
whiptail --title "Error" --msgbox "No hay contenedores LXC disponibles en el sistema." 8 50
exit 1
fi
# Seleccionar CT
CTID=$(whiptail --title "Instalación de JDownloader" --menu "Selecciona el contenedor donde instalar JDownloader:" 20 60 10 $CT_LIST 3>&1 1>&2 2>&3)
if [ -z "$CTID" ]; then
whiptail --title "Cancelado" --msgbox "No se ha seleccionado ningún contenedor." 8 40
exit 1
fi
# Solicitar email
EMAIL=$(whiptail --title "Cuenta My JDownloader" --inputbox "Introduce tu correo electrónico para vincular JDownloader:" 10 60 3>&1 1>&2 2>&3)
if [ -z "$EMAIL" ]; then
whiptail --title "Error" --msgbox "No se ha introducido ningún correo." 8 40
exit 1
fi
# Solicitar contraseña con confirmación
while true; do
PASSWORD=$(whiptail --title "Cuenta My JDownloader" --passwordbox "Introduce tu contraseña de My JDownloader:" 10 60 3>&1 1>&2 2>&3)
[ -z "$PASSWORD" ] && whiptail --title "Error" --msgbox "No se ha introducido ninguna contraseña." 8 40 && exit 1
CONFIRM=$(whiptail --title "Confirmación de contraseña" --passwordbox "Repite tu contraseña para confirmar:" 10 60 3>&1 1>&2 2>&3)
[ "$PASSWORD" = "$CONFIRM" ] && break
whiptail --title "Error" --msgbox "Las contraseñas no coinciden. Intenta de nuevo." 8 50
done
# Confirmación final
whiptail --title "Confirmar datos" --yesno "¿Deseas continuar con los siguientes datos?\n\nCorreo: $EMAIL\nContraseña: (oculta)\n\nEsta información se usará para vincular el contenedor con tu cuenta de My.JDownloader." 14 60
[ $? -ne 0 ] && whiptail --title "Cancelado" --msgbox "Instalación cancelada por el usuario." 8 40 && exit 1
clear
echo "🔍 Detectando sistema operativo dentro del CT $CTID..."
OS_ID=$(pct exec "$CTID" -- awk -F= '/^ID=/{gsub("\"",""); print $2}' /etc/os-release)
echo "Sistema detectado: $OS_ID"
echo "🧰 Preparando entorno..."
case "$OS_ID" in
debian)
# Repositorio adicional para Java 8
pct exec "$CTID" -- wget -q http://www.mirbsd.org/~tg/Debs/sources.txt/wtf-bookworm.sources
pct exec "$CTID" -- mv wtf-bookworm.sources /etc/apt/sources.list.d/
pct exec "$CTID" -- apt update -y
pct exec "$CTID" -- apt install -y openjdk-8-jdk wget
JAVA_PATH="/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java"
;;
ubuntu)
pct exec "$CTID" -- apt update -y
pct exec "$CTID" -- apt install -y openjdk-8-jdk wget
JAVA_PATH="/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java"
;;
alpine)
pct exec "$CTID" -- apk update
pct exec "$CTID" -- apk add openjdk8 wget
JAVA_PATH="/usr/lib/jvm/java-1.8-openjdk/bin/java"
;;
*)
echo "❌ Sistema operativo no soportado: $OS_ID"
exit 1
;;
esac
# Crear carpeta de instalación
pct exec "$CTID" -- mkdir -p /opt/jdownloader
pct exec "$CTID" -- bash -c 'cd /opt/jdownloader && curl -O https://installer.jdownloader.org/JDownloader.jar'
# Crear archivo de configuración JSON para My JDownloader
pct exec "$CTID" -- bash -c "mkdir -p /opt/jdownloader/cfg && cat > /opt/jdownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json" <<EOF
{
"email" : "$EMAIL",
"password" : "$PASSWORD",
"enabled" : true
}
EOF
# Crear servicio según sistema
if [[ "$OS_ID" == "alpine" ]]; then
# Servicio OpenRC para Alpine
pct exec "$CTID" -- bash -c 'cat > /etc/init.d/jdownloader <<EOF
#!/sbin/openrc-run
command="/usr/bin/java"
command_args="-jar /opt/jdownloader/JDownloader.jar -norestart"
pidfile="/var/run/jdownloader.pid"
name="JDownloader"
depend() {
need net
}
EOF'
pct exec "$CTID" -- chmod +x /etc/init.d/jdownloader
pct exec "$CTID" -- rc-update add jdownloader default
pct exec "$CTID" -- rc-service jdownloader start
else
# Servicio systemd para Debian/Ubuntu
pct exec "$CTID" -- bash -c 'cat > /etc/systemd/system/jdownloader.service <<EOF
[Unit]
Description=JDownloader
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/jdownloader
ExecStart=/usr/bin/java -jar JDownloader.jar -norestart
Restart=always
[Install]
WantedBy=multi-user.target
EOF'
pct exec "$CTID" -- systemctl daemon-reexec
pct exec "$CTID" -- systemctl daemon-reload
pct exec "$CTID" -- systemctl enable jdownloader
pct exec "$CTID" -- systemctl start jdownloader
fi
pct exec "$CTID" -- reboot
echo -e "\n\033[1;32m✅ JDownloader se ha instalado correctamente en el CT $CTID y está funcionando como servicio.\033[0m"
echo -e "\n➡ Accede a \033[1;34mhttps://my.jdownloader.org\033[0m con tu cuenta para gestionarlo.\n"

99
scripts/lcx/jd2_.sh Normal file
View File

@ -0,0 +1,99 @@
#!/bin/bash
# Script para instalar JDownloader en un contenedor LXC desde el host Proxmox
# Autor: MacRimi
# Mostrar lista de CTs
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
if [ -z "$CT_LIST" ]; then
whiptail --title "Error" --msgbox "No hay contenedores LXC disponibles en el sistema." 8 50
exit 1
fi
# Seleccionar CT
CTID=$(whiptail --title "Instalación de JDownloader" --menu "Selecciona el contenedor donde instalar JDownloader:" 20 60 10 $CT_LIST 3>&1 1>&2 2>&3)
if [ -z "$CTID" ]; then
whiptail --title "Cancelado" --msgbox "No se ha seleccionado ningún contenedor." 8 40
exit 1
fi
# Solicitar email
EMAIL=$(whiptail --title "Cuenta My JDownloader" --inputbox "Introduce tu correo electrónico para vincular JDownloader:" 10 60 3>&1 1>&2 2>&3)
if [ -z "$EMAIL" ]; then
whiptail --title "Error" --msgbox "No se ha introducido ningún correo." 8 40
exit 1
fi
# Solicitar contraseña
while true; do
PASSWORD=$(whiptail --title "Cuenta My JDownloader" --passwordbox "Introduce tu contraseña de My JDownloader:" 10 60 3>&1 1>&2 2>&3)
if [ -z "$PASSWORD" ]; then
whiptail --title "Error" --msgbox "No se ha introducido ninguna contraseña." 8 40
exit 1
fi
CONFIRM_PASSWORD=$(whiptail --title "Confirmación de contraseña" --passwordbox "Repite tu contraseña para confirmar:" 10 60 3>&1 1>&2 2>&3)
if [ "$PASSWORD" = "$CONFIRM_PASSWORD" ]; then
break
else
whiptail --title "Error" --msgbox "Las contraseñas no coinciden. Intenta de nuevo." 8 50
fi
done
# Confirmar datos
whiptail --title "Confirmar datos" --yesno "¿Deseas continuar con los siguientes datos?\n\nCorreo: $EMAIL\nContraseña: (establecida)\n\nEsta información se usará para vincular el contenedor con tu cuenta de My.JDownloader." 14 60
if [ $? -ne 0 ]; then
whiptail --title "Cancelado" --msgbox "Instalación cancelada por el usuario." 8 40
exit 1
fi
echo
echo "Instalando JDownloader en CT $CTID..."
echo
# Añadir repositorio alternativo para Java 8 y actualizar
pct exec "$CTID" -- wget -q http://www.mirbsd.org/~tg/Debs/sources.txt/wtf-bookworm.sources
pct exec "$CTID" -- mv wtf-bookworm.sources /etc/apt/sources.list.d/
pct exec "$CTID" -- apt update -y
pct exec "$CTID" -- apt install -y openjdk-8-jdk wget
# Crear carpeta y descargar JDownloader
pct exec "$CTID" -- mkdir -p /root/jdownloader
pct exec "$CTID" -- bash -c "cd /root/jdownloader && wget -q http://installer.jdownloader.org/JDownloader.jar"
# Crear archivo de configuración JSON para My JDownloader
pct exec "$CTID" -- bash -c "mkdir -p /root/jdownloader/cfg && cat > /root/jdownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json" <<EOF
{
"email" : "$EMAIL",
"password" : "$PASSWORD",
"enabled" : true
}
EOF
# Crear servicio systemd
pct exec "$CTID" -- bash -c "cat > /etc/systemd/system/jdownloader.service <<EOF
[Unit]
Description=JDownloader Headless
After=network.target
[Service]
Type=simple
WorkingDirectory=/root/jdownloader
ExecStart=/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java -jar JDownloader.jar -norestart
Restart=always
User=root
[Install]
WantedBy=multi-user.target
EOF"
# Activar y arrancar servicio
pct exec "$CTID" -- systemctl daemon-reexec
pct exec "$CTID" -- systemctl daemon-reload
pct exec "$CTID" -- systemctl enable jdownloader
pct exec "$CTID" -- systemctl start jdownloader
echo -e "\n\033[1;32m✅ JDownloader se ha instalado y está funcionando como servicio en el CT $CTID.\033[0m"
echo -e "\nPuedes acceder a \033[1;34mhttps://my.jdownloader.org\033[0m con tu cuenta para gestionarlo.\n"

View File

@ -54,7 +54,7 @@ show_menu() {
if [[ $EXIT_STATUS -ne 0 ]]; then
# ESC pressed or Cancel
clear
msg_ok "$(translate "Thank you for using ProxMenu. Goodbye!")"
msg_ok "$(translate "Thank you for using ProxMenux. Goodbye!")"
rm -f "$TEMP_FILE"
exit 0
fi

View File

@ -13,13 +13,15 @@
# Advanced network management and troubleshooting tool for Proxmox VE.
# Features include interface detection, bridge management, connectivity testing,
# network diagnostics, configuration backup/restore, and automated repairs.
# Special thanks to @Andres_Eduardo_Rojas_Moya for contributing the persistent
# network naming function and for the original idea.
# Configuration ============================================
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
VENV_PATH="/opt/googletrans-env"
BACKUP_DIR="/var/backups/proxmenux"
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
if [[ -f "$UTILS_FILE" ]]; then
source "$UTILS_FILE"
@ -39,10 +41,19 @@ backup_network_config() {
local timestamp=$(date +"%Y-%m-%d_%H-%M-%S")
local backup_file="$BACKUP_DIR/interfaces_backup_$timestamp"
cp /etc/network/interfaces "$backup_file"
msg_ok "$(translate "Network configuration backed up")"
echo "$backup_file"
}
# Tool registration system
ensure_tools_json() {
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
}
register_tool() {
local tool="$1"
local state="$2"
ensure_tools_json
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
}
# ==========================================================
# Network Detection Functions
detect_network_method() {
@ -100,75 +111,6 @@ get_interface_info() {
}
# ==========================================================
# Network Information Functions
show_interface_details() {
NETWORK_METHOD=$(detect_network_method)
if [[ "$NETWORK_METHOD" != "classic" ]]; then
dialog --title "Unsupported Network Stack" \
--msgbox "WARNING: This script only supports the classic Debian/Proxmox network configuration (/etc/network/interfaces).\n\nDetected: $NETWORK_METHOD.\n\nAborting for safety.\n\nPlease configure your network using your distribution's supported tools." 14 70
exit 1
fi
local interfaces=($(detect_all_interfaces))
local info_text=""
info_text+="$(translate "Network Interface Details")\n"
info_text+="$(printf '=%.0s' {1..50})\n\n"
for interface in "${interfaces[@]}"; do
local details=$(get_interface_info "$interface")
IFS='|' read -r name ip status mac <<< "$details"
info_text+="$(translate "Interface"): $name\n"
info_text+=" $(translate "IP Address"): $ip\n"
info_text+=" $(translate "Status"): $status\n"
info_text+=" $(translate "MAC Address"): $mac\n\n"
done
dialog --backtitle "ProxMenux" --title "$(translate "Interface Details")" \
--msgbox "$info_text" 20 70
}
show_bridge_status() {
NETWORK_METHOD=$(detect_network_method)
if [[ "$NETWORK_METHOD" != "classic" ]]; then
dialog --title "Unsupported Network Stack" \
--msgbox "WARNING: This script only supports the classic Debian/Proxmox network configuration (/etc/network/interfaces).\n\nDetected: $NETWORK_METHOD.\n\nAborting for safety.\n\nPlease configure your network using your distribution's supported tools." 14 70
exit 1
fi
local bridges=($(detect_bridge_interfaces))
local bridge_info=""
bridge_info+="$(translate "Bridge Configuration Status")\n"
bridge_info+="$(printf '=%.0s' {1..40})\n\n"
if [ ${#bridges[@]} -eq 0 ]; then
bridge_info+="$(translate "No bridges found")\n"
else
for bridge in "${bridges[@]}"; do
local details=$(get_interface_info "$bridge")
IFS='|' read -r name ip status mac <<< "$details"
# Get bridge ports
local ports=$(grep -A5 "iface $bridge" /etc/network/interfaces 2>/dev/null | grep "bridge-ports" | cut -d' ' -f2-)
[ -z "$ports" ] && ports="$(translate "None")"
bridge_info+="$(translate "Bridge"): $name\n"
bridge_info+=" $(translate "IP"): $ip\n"
bridge_info+=" $(translate "Status"): $status\n"
bridge_info+=" $(translate "Ports"): $ports\n\n"
done
fi
dialog --backtitle "ProxMenux" --title "$(translate "Bridge Status")" \
--msgbox "$bridge_info" 20 70
}
show_routing_table_() {
local route_info=""
@ -428,6 +370,7 @@ analyze_bridge_configuration() {
--textbox "$temp_file" 25 80
rm -f "$temp_file"
# Offer guided repair if issues found
if [ $issues_found -gt 0 ]; then
if dialog --backtitle "ProxMenux" --title "$(translate "Guided Repair Available")" \
@ -437,6 +380,7 @@ analyze_bridge_configuration() {
fi
}
guided_bridge_repair() {
local step=1
local total_steps=5
@ -455,7 +399,8 @@ guided_bridge_repair() {
show_proxmenux_logo
local backup_file=$(backup_network_config)
sleep 1
msg_ok "$(translate "Network configuration backed up")"
sleep 2
dialog --backtitle "ProxMenux" --title "$(translate "Backup Created")" \
--msgbox "$(translate "Safety backup created"): $backup_file\n\n$(translate "You can restore it anytime with"):\ncp $backup_file /etc/network/interfaces" 10 70
@ -580,6 +525,12 @@ guided_bridge_repair() {
fi
}
# ==========================================================
analyze_network_configuration() {
NETWORK_METHOD=$(detect_network_method)
@ -693,7 +644,8 @@ guided_configuration_cleanup() {
show_proxmenux_logo
local backup_file=$(backup_network_config)
sleep 1
msg_ok "$(translate "Network configuration backed up")"
sleep 2
dialog --backtitle "ProxMenux" --title "$(translate "Backup Created")" \
--msgbox "$(translate "Safety backup created"): $backup_file\n\n$(translate "You can restore it anytime with"):\ncp $backup_file /etc/network/interfaces" 10 70
@ -787,6 +739,68 @@ guided_configuration_cleanup() {
}
# ==========================================================
setup_persistent_network() {
local LINK_DIR="/etc/systemd/network"
local BACKUP_DIR="/etc/systemd/network/backup-$(date +%Y%m%d-%H%M%S)"
if ! dialog --title "$(translate "Network Interface Setup")" \
--yesno "\n$(translate "Create persistent network interface names?")" 8 60; then
return 1
fi
show_proxmenux_logo
msg_info "$(translate "Setting up persistent network interfaces")"
sleep 2
# Create directory
mkdir -p "$LINK_DIR"
# Backup existing files
if ls "$LINK_DIR"/*.link >/dev/null 2>&1; then
mkdir -p "$BACKUP_DIR"
cp "$LINK_DIR"/*.link "$BACKUP_DIR"/ 2>/dev/null || true
fi
# Process physical interfaces
local count=0
for iface in $(ls /sys/class/net/ | grep -vE "lo|docker|veth|br-|vmbr|tap|fwpr|fwln|virbr|bond|cilium|zt|wg"); do
if [[ -e "/sys/class/net/$iface/device" ]] || [[ -e "/sys/class/net/$iface/phy80211" ]]; then
local MAC=$(cat /sys/class/net/$iface/address 2>/dev/null)
if [[ "$MAC" =~ ^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$ ]]; then
local LINK_FILE="$LINK_DIR/10-$iface.link"
cat > "$LINK_FILE" <<EOF
[Match]
MACAddress=$MAC
[Link]
Name=$iface
EOF
chmod 644 "$LINK_FILE"
((count++))
fi
fi
done
if [[ $count -gt 0 ]]; then
msg_ok "$(translate "Created persistent names for") $count $(translate "interfaces")"
msg_ok "$(translate "Changes will apply after reboot.")"
else
msg_warn "$(translate "No physical interfaces found")"
fi
register_tool "persistent_network" true
echo -e
msg_success "$(translate "Press ENTER to continue...")"
read -r
}
# ==========================================================
restart_network_service() {
if dialog --title "$(translate "Restart Network")" \
@ -849,7 +863,9 @@ create_network_backup_manual() {
echo -e
msg_info "$(translate "Creating backup of network interfaces configuration...")"
sleep 3
cleanup
backup_network_config
msg_ok "$(translate "Network configuration backed up")"
echo -e
msg_success "$(translate "Press Enter to continue...")"
read -r
@ -923,44 +939,167 @@ restore_network_backup() {
}
# ==========================================================
# Main Menu
show_main_menu() {
while true; do
local selection=$(dialog --clear \
--backtitle "ProxMenux" \
--title "$(translate "Network Management - SAFE MODE")" \
--menu "$(translate "Select an option:"):" 20 70 12 \
"1" "$(translate "Show Interface Details")" \
"2" "$(translate "Show Bridge Status")" \
"3" "$(translate "Show Routing Table")" \
"4" "$(translate "Test Connectivity")" \
"5" "$(translate "Advanced Diagnostics")" \
"6" "$(translate "Analyze Bridge Configuration")" \
"7" "$(translate "Analyze Network Configuration")" \
"8" "$(translate "Restart Network Service")" \
"9" "$(translate "Show Network Config File")" \
"10" "$(translate "Create Network Backup")" \
"11" "$(translate "Restore Network Backup")" \
"0" "$(translate "Return to Main Menu")" \
3>&1 1>&2 2>&3)
launch_iftop() {
if ! command -v iftop &>/dev/null; then
apt-get update -qq && apt-get install -y iftop &>/dev/null
fi
case $selection in
1) show_interface_details ;;
2) show_bridge_status ;;
3) show_routing_table ;;
4) test_connectivity ;;
5) advanced_network_diagnostics ;;
6) analyze_bridge_configuration ;;
7) analyze_network_configuration ;;
8) restart_network_service ;;
9) show_network_config ;;
10) create_network_backup_manual ;;
11) restore_network_backup ;;
0|"") exec bash <(curl -s "$REPO_URL/scripts/menus/main_menu.sh") ;;
esac
dialog --backtitle "ProxMenux" --title "$(translate "iftop usage")" --msgbox "\n$(translate "To exit iftop, press q")" 8 50
clear
iftop
}
launch_iptraf() {
if ! command -v iptraf-ng &>/dev/null; then
apt-get update -qq && apt-get install -y iptraf-ng &>/dev/null
fi
dialog --backtitle "ProxMenux" --title "$(translate "iptraf-ng usage")" --msgbox "\n$(translate "To exit iptraf-ng, press x")" 8 50
clear
iptraf-ng
}
# ==========================================================
confirm_and_run() {
local name="$1"
local command="$2"
dialog --clear --title "$(translate "Confirmation")" \
--yesno "\n\n$(translate "Do you want to run the network script from") $name?" 10 70
response=$?
clear
if [ $response -eq 0 ]; then
eval "$command"
echo
msg_success "$(translate 'Press ENTER to continue...')"
read -r _
else
msg_warn "$(translate "Cancelled by user.")"
sleep 1
fi
}
# ==========================================================
declare -a PROXMENUX_SCRIPTS=(
"Real-time network usage (iftop)||launch_iftop"
"Network monitoring tool (iptraf-ng)||launch_iptraf"
"Show Routing Table||show_routing_table"
"Test Connectivity||test_connectivity"
"Advanced Diagnostics||advanced_network_diagnostics"
"Analyze Bridge Configuration||analyze_bridge_configuration"
"Analyze Network Configuration||analyze_network_configuration"
"Setup Persistent Network Names||setup_persistent_network"
"Restart Network Service||restart_network_service"
"Show Network Config File||show_network_config"
"Create Network Backup||create_network_backup_manual"
"Restore Network Backup||restore_network_backup"
)
declare -a COMMUNITY_SCRIPTS=(
"Disable NIC Offloading (Intel e1000e)|Helper-Scripts|confirm_and_run \"Helper-Scripts\" \"bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/nic-offloading-fix.sh)\""
)
# ==========================================================
format_menu_item() {
local description="$1"
local source="$2"
local total_width=62
local desc_length=${#description}
local source_length=${#source}
local spaces_needed=$((total_width - desc_length - source_length))
[ $spaces_needed -lt 3 ] && spaces_needed=3
local spacing=""
for ((i=0; i<spaces_needed; i++)); do
spacing+=" "
done
echo "${description}${spacing}${source}"
}
# ==========================================================
show_menu() {
while true; do
local menu_items=()
declare -A script_commands
local counter=1
for script in "${PROXMENUX_SCRIPTS[@]}"; do
IFS='|' read -r name source command <<< "$script"
local translated_name="$(translate "$name")"
local formatted_item
formatted_item=$(format_menu_item "$translated_name" "$source")
menu_items+=("$counter" "$formatted_item")
script_commands["$counter"]="$command"
((counter++))
done
menu_items+=("" "")
menu_items+=("-" "───────────────────── $(translate "Community Scripts") ──────────────────────")
menu_items+=("" "")
for script in "${COMMUNITY_SCRIPTS[@]}"; do
IFS='|' read -r name source command <<< "$script"
local translated_name="$(translate "$name")"
local formatted_item
formatted_item=$(format_menu_item "$translated_name" "$source")
menu_items+=("$counter" "$formatted_item")
script_commands["$counter"]="$command"
((counter++))
done
menu_items+=("" "")
menu_items+=("0" "$(translate "Return to Main Menu")")
exec 3>&1
script_selection=$(dialog --clear \
--backtitle "ProxMenux" \
--title "$(translate "Network Management")" \
--menu "\n$(translate "Select a network management option:"):\n" \
26 78 19 \
"${menu_items[@]}" 2>&1 1>&3)
exit_status=$?
exec 3>&-
if [ $exit_status -ne 0 ] || [ "$script_selection" = "0" ]; then
exec bash <(curl -s "$REPO_URL/scripts/menus/main_menu.sh")
fi
if [[ "$script_selection" == "-" || "$script_selection" == "" ]]; then
continue
fi
if [[ -n "${script_commands[$script_selection]}" ]]; then
eval "${script_commands[$script_selection]}"
else
msg_error "$(translate "Invalid selection")"
sleep 1
fi
done
}
# ==========================================================
show_main_menu
show_menu

View File

@ -68,320 +68,99 @@ register_tool() {
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
}
# ==========================================================
lvm_repair_check() {
msg_info "$(translate "Checking and repairing old LVM PV headers (if needed)...")"
pvs_output=$(LC_ALL=C pvs -v 2>&1 | grep "old PV header")
if [ -z "$pvs_output" ]; then
msg_ok "$(translate "No PVs with old headers found.")"
register_tool "lvm_repair" true
return
check_extremeshok_warning() {
local marker_file="/etc/extremeshok"
if [[ -f "$marker_file" ]]; then
dialog --backtitle "ProxMenux" --title "xshok-proxmox Post-Install Detected" \
--yesno "\n$(translate "It appears that you have already executed the xshok-proxmox post-install script on this system.")\n\n\
$(translate "If you continue, some adjustments may be duplicated or conflict with those already made by xshok.")\n\n\
$(translate "Do you want to continue anyway?")" 13 70
local response=$?
if [[ $response -ne 0 ]]; then
show_proxmenux_logo
msg_warn "$(translate "Action cancelled due to previous xshok-proxmox modifications.")"
echo -e
msg_success "$(translate "Press Enter to return to menu...")"
read -r
exit 1
fi
fi
declare -A vg_map
while read -r line; do
pv=$(echo "$line" | grep -o '/dev/[^ ]*')
vg=$(pvs -o vg_name --noheadings "$pv" | awk '{print $1}')
if [ -n "$vg" ]; then
vg_map["$vg"]=1
fi
done <<< "$pvs_output"
for vg in "${!vg_map[@]}"; do
msg_warn "$(translate "Old PV header(s) found in VG $vg. Updating metadata...")"
vgck --updatemetadata "$vg"
vgchange -ay "$vg"
if [ $? -ne 0 ]; then
msg_warn "$(translate "Metadata update failed for VG $vg. Review manually.")"
else
msg_ok "$(translate "Metadata updated successfully for VG $vg")"
fi
done
msg_ok "$(translate "LVM PV headers check completed")"
}
# ==========================================================
cleanup_duplicate_repos() {
local sources_file="/etc/apt/sources.list"
local temp_file=$(mktemp)
local cleaned_count=0
declare -A seen_repos
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "$line" ]]; then
echo "$line" >> "$temp_file"
continue
fi
if [[ "$line" =~ ^deb ]]; then
read -r _ url dist components <<< "$line"
local key="${url}_${dist}"
if [[ -v "seen_repos[$key]" ]]; then
echo "# $line" >> "$temp_file"
cleaned_count=$((cleaned_count + 1))
else
echo "$line" >> "$temp_file"
seen_repos[$key]="$components"
fi
else
echo "$line" >> "$temp_file"
fi
done < "$sources_file"
mv "$temp_file" "$sources_file"
chmod 644 "$sources_file"
local pve_files=(/etc/apt/sources.list.d/*proxmox*.list /etc/apt/sources.list.d/*pve*.list)
local pve_content="deb http://download.proxmox.com/debian/pve ${OS_CODENAME} pve-no-subscription"
local pve_public_repo="/etc/apt/sources.list.d/pve-public-repo.list"
local pve_public_repo_exists=false
if [ -f "$pve_public_repo" ] && grep -q "^deb.*pve-no-subscription" "$pve_public_repo"; then
pve_public_repo_exists=true
fi
for file in "${pve_files[@]}"; do
if [ -f "$file" ] && grep -q "^deb.*pve-no-subscription" "$file"; then
if ! $pve_public_repo_exists && [[ "$file" == "$pve_public_repo" ]]; then
sed -i 's/^# *deb/deb/' "$file"
pve_public_repo_exists=true
elif [[ "$file" != "$pve_public_repo" ]]; then
sed -i 's/^deb/# deb/' "$file"
cleaned_count=$((cleaned_count + 1))
fi
fi
done
apt update
}
apt_upgrade() {
local pve_version
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
NECESSARY_REBOOT=1
if [ -f /etc/apt/sources.list.d/pve-enterprise.list ] && grep -q "^deb" /etc/apt/sources.list.d/pve-enterprise.list; then
msg_info "$(translate "Disabling enterprise Proxmox repository...")"
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/pve-enterprise.list
msg_ok "$(translate "Enterprise Proxmox repository disabled")"
fi
if [ -f /etc/apt/sources.list.d/ceph.list ] && grep -q "^deb" /etc/apt/sources.list.d/ceph.list; then
msg_info "$(translate "Disabling enterprise Proxmox Ceph repository...")"
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/ceph.list
msg_ok "$(translate "Enterprise Proxmox Ceph repository disabled")"
fi
if [ ! -f /etc/apt/sources.list.d/pve-public-repo.list ] || ! grep -q "pve-no-subscription" /etc/apt/sources.list.d/pve-public-repo.list; then
msg_info "$(translate "Enabling free public Proxmox repository...")"
echo "deb http://download.proxmox.com/debian/pve ${OS_CODENAME} pve-no-subscription" > /etc/apt/sources.list.d/pve-public-repo.list
msg_ok "$(translate "Free public Proxmox repository enabled")"
fi
sources_file="/etc/apt/sources.list"
need_update=false
sed -i 's|ftp.es.debian.org|deb.debian.org|g' "$sources_file"
if grep -q "^deb http://security.debian.org ${OS_CODENAME}-security main contrib" "$sources_file"; then
sed -i "s|^deb http://security.debian.org ${OS_CODENAME}-security main contrib|deb http://security.debian.org/debian-security ${OS_CODENAME}-security main contrib non-free non-free-firmware|" "$sources_file"
msg_ok "$(translate "Replaced security repository with full version")"
need_update=true
fi
if ! grep -q "deb http://security.debian.org/debian-security ${OS_CODENAME}-security" "$sources_file"; then
echo "deb http://security.debian.org/debian-security ${OS_CODENAME}-security main contrib non-free non-free-firmware" >> "$sources_file"
need_update=true
fi
if ! grep -q "deb http://deb.debian.org/debian ${OS_CODENAME} " "$sources_file"; then
echo "deb http://deb.debian.org/debian ${OS_CODENAME} main contrib non-free non-free-firmware" >> "$sources_file"
need_update=true
fi
if ! grep -q "deb http://deb.debian.org/debian ${OS_CODENAME}-updates" "$sources_file"; then
echo "deb http://deb.debian.org/debian ${OS_CODENAME}-updates main contrib non-free non-free-firmware" >> "$sources_file"
need_update=true
fi
msg_ok "$(translate "Debian repositories configured correctly")"
# ===================================================
if [ ! -f /etc/apt/apt.conf.d/no-bookworm-firmware.conf ]; then
msg_info "$(translate "Disabling non-free firmware warnings...")"
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' > /etc/apt/apt.conf.d/no-bookworm-firmware.conf
msg_ok "$(translate "Non-free firmware warnings disabled")"
fi
msg_info "$(translate "Updating package lists...")"
if apt-get update > /dev/null 2>&1; then
msg_ok "$(translate "Package lists updated")"
else
msg_error "$(translate "Failed to update package lists")"
if [[ -z "$pve_version" ]]; then
msg_error "Unable to detect Proxmox version."
return 1
fi
if [[ "$pve_version" -ge 9 ]]; then
msg_info "$(translate "Removing conflicting utilities...")"
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' purge ntp openntpd systemd-timesyncd > /dev/null 2>&1; then
msg_ok "$(translate "Conflicting utilities removed")"
bash <(curl -fsSL "$REPO_URL/scripts/global/update-pve.sh")
else
msg_error "$(translate "Failed to remove conflicting utilities")"
bash <(curl -fsSL "$REPO_URL/scripts/global/update-pve8.sh")
fi
msg_info "$(translate "Performing packages upgrade...")"
apt-get install pv -y > /dev/null 2>&1
total_packages=$(apt-get -s dist-upgrade | grep "^Inst" | wc -l)
if [ "$total_packages" -eq 0 ]; then
total_packages=1
fi
msg_ok "$(translate "Packages upgrade successfull")"
tput civis
tput sc
(
/usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' dist-upgrade 2>&1 | \
while IFS= read -r line; do
if [[ "$line" =~ ^(Setting up|Unpacking|Preparing to unpack|Processing triggers for) ]]; then
package_name=$(echo "$line" | sed -E 's/.*(Setting up|Unpacking|Preparing to unpack|Processing triggers for) ([^ ]+).*/\2/')
[ -z "$package_name" ] && package_name="$(translate "Unknown")"
tput rc
tput ed
row=$(( $(tput lines) - 6 ))
tput cup $row 0; echo "$(translate "Installing packages...")"
tput cup $((row + 1)) 0; echo "──────────────────────────────────────────────"
tput cup $((row + 2)) 0; echo "Package: $package_name"
tput cup $((row + 3)) 0; echo "Progress: [ ] 0%"
tput cup $((row + 4)) 0; echo "──────────────────────────────────────────────"
for i in $(seq 1 10); do
progress=$((i * 10))
tput cup $((row + 3)) 9
printf "[%-50s] %3d%%" "$(printf "#%.0s" $(seq 1 $((progress/2))))" "$progress"
done
fi
done
)
if [ $? -eq 0 ]; then
tput rc
tput ed
msg_ok "$(translate "System upgrade completed")"
fi
msg_info "$(translate "Installing additional Proxmox packages...")"
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' install zfsutils-linux proxmox-backup-restore-image chrony > /dev/null 2>&1; then
msg_ok "$(translate "Additional Proxmox packages installed")"
else
msg_error "$(translate "Failed to install additional Proxmox packages")"
fi
lvm_repair_check
cleanup_duplicate_repos
msg_ok "$(translate "Proxmox update completed")"
}
# ==========================================================
remove_subscription_banner_() {
msg_info "$(translate "Removing Proxmox subscription nag banner...")"
local JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
local GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
local APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
if [[ ! -f "$APT_HOOK" ]]; then
cat <<'EOF' > "$APT_HOOK"
DPkg::Post-Invoke { "dpkg -V proxmox-widget-toolkit | grep -q '/proxmoxlib\.js$'; if [ $? -eq 1 ]; then { echo 'Removing subscription nag from UI...'; sed -i '/.*data\.status.*{/{s/\!//;s/active/NoMoreNagging/;s/Active/NoMoreNagging/}' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; rm -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz; }; fi"; };
EOF
fi
if [[ -f "$JS_FILE" ]]; then
sed -i '/.*data\.status.*{/{s/\!//;s/active/NoMoreNagging/;s/Active/NoMoreNagging/}' "$JS_FILE"
[[ -f "$GZ_FILE" ]] && rm -f "$GZ_FILE"
touch "$JS_FILE"
fi
apt --reinstall install proxmox-widget-toolkit -y > /dev/null 2>&1
msg_ok "$(translate "Subscription nag banner removed successfully")"
register_tool "subscription_banner" true
}
remove_subscription_banner() {
local JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
local GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
local APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
local pve_version
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
# Detect if already applied
if grep -q "NoMoreNagging" "$JS_FILE" 2>/dev/null && [[ -f "$APT_HOOK" ]]; then
# Already applied, just reapply silently
:
else
# Ask user
if ! whiptail --title "$(translate "Proxmox Subscription Banner")" \
--yesno "$(translate "Do you want to remove the Proxmox subscription banner from the web interface?")" 10 60; then
msg_warn "$(translate "Banner removal cancelled by user.")"
if [[ -z "$pve_version" ]]; then
msg_error "Unable to detect Proxmox version."
return 1
fi
if [[ "$pve_version" -ge 9 ]]; then
if ! whiptail --title "Proxmox VE 9.x Subscription Banner Removal" \
--yesno "Do you want to remove the Proxmox subscription banner from the web interface for PVE $pve_version?" 10 70; then
msg_warn "Banner removal cancelled by user."
return 1
fi
bash <(curl -fsSL "$REPO_URL/scripts/global/remove-banner-pve9.sh")
else
if ! whiptail --title "Proxmox VE 8.x Subscription Banner Removal" \
--yesno "Do you want to remove the Proxmox subscription banner from the web interface for PVE $pve_version?" 10 70; then
msg_warn "Banner removal cancelled by user."
return 1
fi
bash <(curl -fsSL "$REPO_URL/scripts/global/remove-banner-pve8.sh")
fi
msg_info "$(translate "Removing Proxmox subscription nag banner...")"
if [[ ! -f "$APT_HOOK" ]]; then
cat <<'EOF' > "$APT_HOOK"
DPkg::Post-Invoke { "dpkg -V proxmox-widget-toolkit | grep -q '/proxmoxlib\.js$'; if [ $? -eq 1 ]; then { echo 'Removing subscription nag from UI...'; sed -i '/.*data\.status.*{/{s/\!//;s/active/NoMoreNagging/;s/Active/NoMoreNagging/}' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; rm -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz; }; fi"; };
EOF
fi
if [[ -f "$JS_FILE" ]]; then
sed -i '/.*data\.status.*{/{s/\!//;s/active/NoMoreNagging/;s/Active/NoMoreNagging/}' "$JS_FILE"
[[ -f "$GZ_FILE" ]] && rm -f "$GZ_FILE"
touch "$JS_FILE"
fi
apt --reinstall install proxmox-widget-toolkit -y > /dev/null 2>&1
msg_ok "$(translate "Subscription nag banner removed successfully")"
register_tool "subscription_banner" true
}
# ==========================================================
@ -713,7 +492,7 @@ disable_rpc() {
}
# ==========================================================
customize_bashrc() {
customize_bashrc_() {
msg_info "$(translate "Customizing bashrc for root user...")"
local bashrc="/root/.bashrc"
local bash_profile="/root/.bash_profile"
@ -746,53 +525,149 @@ EOF
register_tool "bashrc_custom" true
}
customize_bashrc() {
msg_info "$(translate "Customizing bashrc for root user...")"
local bashrc="/root/.bashrc"
local bash_profile="/root/.bash_profile"
local marker_begin="# BEGIN PMX_CORE_BASHRC"
local marker_end="# END PMX_CORE_BASHRC"
[ -f "${bashrc}.bak" ] || cp "$bashrc" "${bashrc}.bak" > /dev/null 2>&1
if grep -q "^${marker_begin}$" "$bashrc" 2>/dev/null; then
sed -i "/^${marker_begin}$/,/^${marker_end}$/d" "$bashrc"
fi
cat >> "$bashrc" << 'EOF'
${marker_begin}
# ProxMenux core customizations
export HISTTIMEFORMAT="%d/%m/%y %T "
export PS1="\[\e[31m\][\[\e[m\]\[\e[38;5;172m\]\u\[\e[m\]@\[\e[38;5;153m\]\h\[\e[m\] \[\e[38;5;214m\]\W\[\e[m\]\[\e[31m\]]\[\e[m\]\\$ "
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
source /etc/profile.d/bash_completion.sh
${marker_end}
EOF
if ! grep -q "source /root/.bashrc" "$bash_profile" 2>/dev/null; then
echo "source /root/.bashrc" >> "$bash_profile" 2>/dev/null
fi
msg_ok "$(translate "Bashrc customization completed")"
register_tool "bashrc_custom" true
}
# ==========================================================
install_log2ram_auto() {
msg_info "$(translate "Checking if system disk is SSD or M.2...")"
ROOT_PART=$(lsblk -no NAME,MOUNTPOINT | grep ' /$' | awk '{print $1}')
SYSTEM_DISK=$(lsblk -no PKNAME /dev/$ROOT_PART 2>/dev/null)
SYSTEM_DISK=${SYSTEM_DISK:-sda}
msg_info "$(translate "Checking if system disk is SSD or M.2...")"
if [[ "$SYSTEM_DISK" == nvme* || "$(cat /sys/block/$SYSTEM_DISK/queue/rotational 2>/dev/null)" == "0" ]]; then
msg_ok "$(translate "System disk ($SYSTEM_DISK) is SSD or M.2. Proceeding with Log2RAM setup.")"
local is_ssd=false
local pool disks disk byid_path dev rot
if grep -qE '^root=ZFS=' /etc/kernel/cmdline 2>/dev/null || mount | grep -q 'on / type zfs'; then
pool=$(zfs list -Ho name,mountpoint 2>/dev/null | awk '$2=="/"{print $1}' | cut -d/ -f1)
disks=$(zpool status "$pool" 2>/dev/null | awk '/ONLINE/ && $1 !~ /:|mirror|raidz|log|spare|config|NAME|rpool|state/ {print $1}' | sort -u)
is_ssd=true
for disk in $disks; do
byid_path=$(readlink -f /dev/disk/by-id/*$disk* 2>/dev/null) || continue
dev=$(basename "$byid_path" | sed -E 's|[0-9]+$||' | sed -E 's|p$||')
rot=$(cat /sys/block/$dev/queue/rotational 2>/dev/null)
[[ "$rot" != "0" ]] && is_ssd=false && break
done
else
msg_warn "$(translate "System disk ($SYSTEM_DISK) is not SSD/M.2. Skipping Log2RAM installation.")"
ROOT_PART=$(lsblk -no NAME,MOUNTPOINT | grep ' /$' | awk '{print $1}')
SYSTEM_DISK=$(lsblk -no PKNAME /dev/$ROOT_PART 2>/dev/null)
SYSTEM_DISK=${SYSTEM_DISK:-sda}
if [[ "$SYSTEM_DISK" == nvme* || "$(cat /sys/block/$SYSTEM_DISK/queue/rotational 2>/dev/null)" == "0" ]]; then
is_ssd=true
fi
fi
if [[ "$is_ssd" == true ]]; then
msg_ok "$(translate "System disk is SSD or M.2. Proceeding with Log2RAM setup.")"
else
msg_warn "$(translate "System disk is not SSD/M.2. Skipping Log2RAM installation.")"
return 0
fi
# Clean up previous state
rm -rf /tmp/log2ram
rm -f /etc/systemd/system/log2ram*
rm -f /etc/systemd/system/log2ram-daily.*
rm -f /etc/cron.d/log2ram*
rm -f /usr/sbin/log2ram
rm -f /etc/log2ram.conf
rm -f /usr/local/bin/log2ram-check.sh
rm -rf /var/log.hdd
systemctl daemon-reexec >/dev/null 2>&1
systemctl daemon-reload >/dev/null 2>&1
msg_info "$(translate "Installing log2ram from GitHub...")"
if ! command -v git >/dev/null 2>&1; then
apt-get update -qq >/dev/null 2>&1
apt-get install -y git >/dev/null 2>&1
if [[ -f /etc/log2ram.conf ]] && command -v log2ram >/dev/null 2>&1 && systemctl list-units --all | grep -q log2ram; then
msg_ok "$(translate "Log2RAM is already installed and configured correctly.")"
register_tool "log2ram" true
return 0
fi
git clone https://github.com/azlux/log2ram.git /tmp/log2ram >/dev/null 2>>/tmp/log2ram_install.log
cd /tmp/log2ram || return 1
bash install.sh >>/tmp/log2ram_install.log 2>&1
msg_info "$(translate "Log2RAM proceeding with installation...")"
if [[ -f /etc/log2ram.conf ]] && systemctl list-units --all | grep -q log2ram; then
msg_ok "$(translate "Log2RAM installed successfully")"
else
msg_error "$(translate "Failed to install Log2RAM. See /tmp/log2ram_install.log")"
if [[ -d /tmp/log2ram ]]; then
rm -rf /tmp/log2ram
fi
[[ -f /etc/systemd/system/log2ram.service ]] && rm -f /etc/systemd/system/log2ram*
[[ -f /etc/systemd/system/log2ram-daily.service ]] && rm -f /etc/systemd/system/log2ram-daily.*
[[ -f /etc/cron.d/log2ram ]] && rm -f /etc/cron.d/log2ram*
[[ -f /usr/sbin/log2ram ]] && rm -f /usr/sbin/log2ram
[[ -f /etc/log2ram.conf ]] && rm -f /etc/log2ram.conf
[[ -f /usr/local/bin/log2ram-check.sh ]] && rm -f /usr/local/bin/log2ram-check.sh
[[ -d /var/log.hdd ]] && rm -rf /var/log.hdd
systemctl daemon-reexec >/dev/null 2>&1 || true
systemctl daemon-reload >/dev/null 2>&1 || true
if ! command -v git >/dev/null 2>&1; then
apt-get update -qq >/dev/null 2>&1
apt-get install -y git >/dev/null 2>&1
msg_ok "$(translate "Git installed successfully")"
fi
if ! git clone https://github.com/azlux/log2ram.git /tmp/log2ram >/dev/null 2>>/tmp/log2ram_install.log; then
msg_error "$(translate "Failed to clone log2ram repository. Check /tmp/log2ram_install.log")"
return 1
fi
# Detect RAM
cd /tmp/log2ram || {
msg_error "$(translate "Failed to access log2ram directory")"
return 1
}
if ! bash install.sh >>/tmp/log2ram_install.log 2>&1; then
msg_error "$(translate "Failed to run log2ram installer. Check /tmp/log2ram_install.log")"
return 1
fi
if [[ -f /etc/log2ram.conf ]] && command -v log2ram >/dev/null 2>&1; then
msg_ok "$(translate "Log2RAM installed successfully")"
else
msg_error "$(translate "Log2RAM installation verification failed. Check /tmp/log2ram_install.log")"
return 1
fi
RAM_SIZE_GB=$(free -g | awk '/^Mem:/{print $2}')
[[ -z "$RAM_SIZE_GB" || "$RAM_SIZE_GB" -eq 0 ]] && RAM_SIZE_GB=4
@ -809,10 +684,21 @@ install_log2ram_auto() {
msg_ok "$(translate "Detected RAM:") $RAM_SIZE_GB GB — $(translate "Log2RAM size set to:") $LOG2RAM_SIZE"
sed -i "s/^SIZE=.*/SIZE=$LOG2RAM_SIZE/" /etc/log2ram.conf
LOG2RAM_BIN="$(command -v log2ram || echo /usr/local/bin/log2ram)"
rm -f /etc/cron.daily/log2ram /etc/cron.weekly/log2ram /etc/cron.monthly/log2ram 2>/dev/null || true
rm -f /etc/cron.hourly/log2ram
echo "0 */$CRON_HOURS * * * root /usr/sbin/log2ram write" > /etc/cron.d/log2ram
msg_ok "$(translate "log2ram write scheduled every") $CRON_HOURS $(translate "hour(s)")"
{
echo 'MAILTO=""'
echo "0 */$CRON_HOURS * * * root $LOG2RAM_BIN write >/dev/null 2>&1"
} > /etc/cron.d/log2ram
chmod 0644 /etc/cron.d/log2ram
chown root:root /etc/cron.d/log2ram
msg_ok "$(translate "Log2RAM write scheduled every") $CRON_HOURS $(translate "hour(s)")"
cat << 'EOF' > /usr/local/bin/log2ram-check.sh
#!/bin/bash
@ -820,19 +706,77 @@ CONF_FILE="/etc/log2ram.conf"
LIMIT_KB=$(grep '^SIZE=' "$CONF_FILE" | cut -d'=' -f2 | tr -d 'M')000
USED_KB=$(df /var/log --output=used | tail -1)
THRESHOLD=$(( LIMIT_KB * 90 / 100 ))
if (( USED_KB > THRESHOLD )); then
/usr/sbin/log2ram write
$(command -v log2ram) write
fi
EOF
chmod +x /usr/local/bin/log2ram-check.sh
echo "*/5 * * * * root /usr/local/bin/log2ram-check.sh" > /etc/cron.d/log2ram-auto-sync
{
echo 'MAILTO=""'
echo "*/5 * * * * root /usr/local/bin/log2ram-check.sh >/dev/null 2>&1"
} > /etc/cron.d/log2ram-auto-sync
chmod 0644 /etc/cron.d/log2ram-auto-sync
chown root:root /etc/cron.d/log2ram-auto-sync
msg_ok "$(translate "Auto-sync enabled when /var/log exceeds 90% of") $LOG2RAM_SIZE"
register_tool "log2ram" true
}
# ==========================================================
setup_persistent_network() {
local LINK_DIR="/etc/systemd/network"
local BACKUP_DIR="/etc/systemd/network/backup-$(date +%Y%m%d-%H%M%S)"
msg_info "$(translate "Setting up persistent network interfaces")"
sleep 2
mkdir -p "$LINK_DIR"
if ls "$LINK_DIR"/*.link >/dev/null 2>&1; then
mkdir -p "$BACKUP_DIR"
cp "$LINK_DIR"/*.link "$BACKUP_DIR"/ 2>/dev/null || true
fi
local count=0
for iface in $(ls /sys/class/net/ | grep -vE "lo|docker|veth|br-|vmbr|tap|fwpr|fwln|virbr|bond|cilium|zt|wg"); do
if [[ -e "/sys/class/net/$iface/device" ]] || [[ -e "/sys/class/net/$iface/phy80211" ]]; then
local MAC=$(cat /sys/class/net/$iface/address 2>/dev/null)
if [[ "$MAC" =~ ^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$ ]]; then
local LINK_FILE="$LINK_DIR/10-$iface.link"
cat > "$LINK_FILE" <<EOF
[Match]
MACAddress=$MAC
[Link]
Name=$iface
EOF
chmod 644 "$LINK_FILE"
((count++))
fi
fi
done
if [[ $count -gt 0 ]]; then
msg_ok "$(translate "Created persistent names for") $count $(translate "interfaces")"
msg_ok "$(translate "Changes will apply after reboot.")"
else
msg_warn "$(translate "No physical interfaces found")"
fi
register_tool "persistent_network" true
}
# ==========================================================
run_complete_optimization() {
@ -857,6 +801,7 @@ run_complete_optimization() {
disable_rpc
customize_bashrc
install_log2ram_auto
setup_persistent_network
echo -e
@ -888,7 +833,7 @@ run_complete_optimization() {
}
check_extremeshok_warning
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
run_complete_optimization
fi

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,7 @@ register_tool() {
################################################################
uninstall_fastfetch() {
if ! command -v fastfetch &>/dev/null; then
if ! command -v fastfetch &>/dev/null && [[ ! -f /usr/local/bin/fastfetch ]]; then
msg_warn "$(translate "Fastfetch is not installed.")"
return 0
fi
@ -58,7 +58,8 @@ uninstall_fastfetch() {
rm -f /usr/local/bin/fastfetch /usr/bin/fastfetch
rm -rf "$HOME/.config/fastfetch"
rm -rf /usr/local/share/fastfetch
sed -i '/fastfetch/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null
sed -i '/fastfetch/d' "$HOME/.bashrc" "$HOME/.profile" /etc/profile 2>/dev/null
sed -i '/# BEGIN FASTFETCH/,/# END FASTFETCH/d' "$HOME/.bashrc"
rm -f /etc/profile.d/fastfetch.sh /etc/update-motd.d/99-fastfetch
dpkg -r fastfetch &>/dev/null
@ -68,7 +69,7 @@ uninstall_fastfetch() {
################################################################
uninstall_figurine() {
uninstall_figurine_() {
if ! command -v figurine &>/dev/null; then
msg_warn "$(translate "Figurine is not installed.")"
return 0
@ -83,6 +84,26 @@ uninstall_figurine() {
register_tool "figurine" false
}
uninstall_figurine() {
if ! command -v figurine &>/dev/null; then
msg_warn "$(translate "Figurine is not installed.")"
return 0
fi
msg_info2 "$(translate "Uninstalling Figurine...")"
rm -f /usr/local/bin/figurine
rm -f /etc/profile.d/figurine.sh
sed -i '/lxcclean/d;/lxcupdate/d;/kernelclean/d;/cpugov/d;/updatecerts/d;/seqwrite/d;/seqread/d;/ranwrite/d;/ranread/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null
sed -i '/# ProxMenux Figurine aliases and tools/,+20d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null
sed -i '/# BEGIN PROXMENUX ALIASES/,/# END PROXMENUX ALIASES/d' "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null
msg_ok "$(translate "Figurine removed from system")"
register_tool "figurine" false
}
################################################################
uninstall_kexec() {
@ -445,6 +466,29 @@ uninstall_log2ram() {
register_tool "log2ram" false
}
################################################################
uninstall_persistent_network() {
local LINK_DIR="/etc/systemd/network"
msg_info "$(translate "Removing all .link files from") $LINK_DIR"
sleep 2
if ! ls "$LINK_DIR"/*.link >/dev/null 2>&1; then
msg_warn "$(translate "No .link files found in") $LINK_DIR"
return 0
fi
rm -f "$LINK_DIR"/*.link
msg_ok "$(translate "Removed all .link files from") $LINK_DIR"
msg_info "$(translate "Interface names will return to default systemd behavior.")"
register_tool "persistent_network" false
}
################################################################
migrate_installed_tools() {
@ -553,10 +597,14 @@ show_uninstall_menu() {
memory_settings) desc="Memory Settings Optimization";;
kernel_panic) desc="Kernel Panic Configuration";;
apt_ipv4) desc="APT IPv4 Force";;
kexec) desc="kexec for quick reboots";;
network_optimization) desc="Network Optimizations";;
disable_rpc) desc="RPC/rpcbind Disable";;
bashrc_custom) desc="Bashrc Customization";;
figurine) desc="Figurine";;
fastfetch) desc="Fastfetch";;
log2ram) desc="Log2ram (SSD Protection)";;
persistent_network) desc="Setting persistent network interfaces";;
*) desc="$tool";;
esac
menu_options+=("$tool" "$desc" "off")

View File

@ -1,13 +1,12 @@
#!/bin/bash
# ==========================================================
# ProxMenu - A menu-driven script for Proxmox VE management
# ==========================================================
# Author : MacRimi
# Copyright : (c) 2024 MacRimi
# License : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE)
# Version : 1.1
# Last Updated: 28/06/2025
# Version : 1.2
# Last Updated: 30/07/2025
# ==========================================================
# Description:
# This script allows users to assign physical disks to existing
@ -17,6 +16,7 @@
# - Identifies and displays unassigned physical disks.
# - Allows the user to select multiple disks and attach them to a CT.
# - Configures the selected disks for the CT and verifies the assignment.
# - Uses persistent device paths to avoid issues with device order changes.
# ==========================================================
# Configuration ============================================
@ -32,8 +32,66 @@ fi
load_language
initialize_cache
# Get OS codename for repository configuration
OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs )"
# ==========================================================
# Function to get persistent device path
get_persistent_path() {
local device="$1"
local persistent_path=""
# Try by-id first (most reliable)
for path in /dev/disk/by-id/*; do
if [[ -e "$path" && "$(readlink -f "$path")" == "$device" ]]; then
# Prefer ata- or scsi- over wwn- for readability
if [[ "$path" =~ ata-|scsi- ]]; then
echo "$path"
return 0
elif [[ -z "$persistent_path" ]]; then
persistent_path="$path"
fi
fi
done
# Return the first found by-id path if any
if [[ -n "$persistent_path" ]]; then
echo "$persistent_path"
return 0
fi
# Try by-path as fallback
for path in /dev/disk/by-path/*; do
if [[ -e "$path" && "$(readlink -f "$path")" == "$device" ]]; then
echo "$path"
return 0
fi
done
# Fallback to original device if no persistent path found
msg_warn "$(translate "No persistent path found for") $device, $(translate "using direct path")"
echo "$device"
}
# Function to ensure repositories are properly configured
ensure_repositories() {
local sources_file="/etc/apt/sources.list"
local need_update=false
# Only verify the main repository with contrib and non-free
if ! grep -q "deb.*${OS_CODENAME}.*main" "$sources_file"; then
echo "deb http://deb.debian.org/debian ${OS_CODENAME} main contrib non-free non-free-firmware" >> "$sources_file"
need_update=true
fi
if [ "$need_update" = true ]; then
apt update >/dev/null 2>&1
fi
return 0
}
get_disk_info() {
local disk=$1
MODEL=$(lsblk -dn -o MODEL "$disk" | xargs)
@ -41,8 +99,10 @@ get_disk_info() {
echo "$MODEL" "$SIZE"
}
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
# Ensure repositories are configured
ensure_repositories
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
if [ -z "$CT_LIST" ]; then
whiptail --title "$(translate "Error")" --msgbox "$(translate "No CTs available in the system.")" 8 40
exit 1
@ -60,12 +120,11 @@ CTID=$(echo "$CTID" | tr -d '"')
clear
show_proxmenux_logo
echo -e
msg_info2 "$(translate "Add Disk") Passthrough $(translate "to a LXC")"
msg_title "$(translate "Add Disk") Passthrough $(translate "to a LXC")"
echo -e
msg_ok "$(translate "CT selected successfully.")"
CT_STATUS=$(pct status "$CTID" | awk '{print $2}')
if [ "$CT_STATUS" != "running" ]; then
msg_info "$(translate "Starting CT") $CTID..."
pct start "$CTID"
@ -79,10 +138,10 @@ if [ "$CT_STATUS" != "running" ]; then
fi
CONF_FILE="/etc/pve/lxc/$CTID.conf"
if grep -q '^unprivileged: 1' "$CONF_FILE"; then
if whiptail --title "$(translate "Privileged Container")" \
--yesno "$(translate "The selected container is unprivileged. A privileged container is required for direct device passthrough.")\\n\\n$(translate "Do you want to convert it to a privileged container now?")" 12 70; then
msg_info "$(translate "Stopping container") $CTID..."
pct shutdown "$CTID" &>/dev/null
for i in {1..10}; do
@ -91,15 +150,18 @@ if grep -q '^unprivileged: 1' "$CONF_FILE"; then
break
fi
done
if [ "$(pct status "$CTID" | awk '{print $2}')" == "running" ]; then
msg_error "$(translate "Failed to stop the container.")"
exit 1
fi
msg_ok "$(translate "Container stopped.")"
cp "$CONF_FILE" "$CONF_FILE.bak"
sed -i '/^unprivileged: 1/d' "$CONF_FILE"
echo "unprivileged: 0" >> "$CONF_FILE"
msg_ok "$(translate "Container successfully converted to privileged.")"
msg_info "$(translate "Starting container") $CTID..."
pct start "$CTID" &>/dev/null
sleep 2
@ -123,7 +185,6 @@ MOUNTED_DISKS=$(lsblk -ln -o NAME,MOUNTPOINT | awk '$2!="" {print "/dev/" $1}')
ZFS_DISKS=""
ZFS_RAW=$(zpool list -v -H 2>/dev/null | awk '{print $1}' | grep -v '^NAME$' | grep -v '^-' | grep -v '^mirror')
for entry in $ZFS_RAW; do
path=""
if [[ "$entry" == wwn-* || "$entry" == ata-* ]]; then
@ -133,6 +194,7 @@ for entry in $ZFS_RAW; do
elif [[ "$entry" == /dev/* ]]; then
path="$entry"
fi
if [ -n "$path" ]; then
base_disk=$(lsblk -no PKNAME "$path" 2>/dev/null)
if [ -n "$base_disk" ]; then
@ -140,7 +202,6 @@ for entry in $ZFS_RAW; do
fi
fi
done
ZFS_DISKS=$(echo "$ZFS_DISKS" | sort -u)
is_disk_in_use() {
@ -154,6 +215,7 @@ is_disk_in_use() {
return 0
fi
done < <(lsblk -ln -o NAME,FSTYPE "$disk" | tail -n +2)
if echo "$USED_DISKS" | grep -q "$disk" || echo "$ZFS_DISKS" | grep -q "$disk"; then
return 0
fi
@ -166,6 +228,7 @@ RAID_ACTIVE=$(grep -Po 'md\d+\s*:\s*active\s+raid[0-9]+' /proc/mdstat | awk '{pr
while read -r DISK; do
[[ "$DISK" =~ /dev/zd ]] && continue
INFO=($(get_disk_info "$DISK"))
MODEL="${INFO[@]::${#INFO[@]}-1}"
SIZE="${INFO[-1]}"
@ -193,6 +256,7 @@ while read -r DISK; do
USED_BY=""
REAL_PATH=$(readlink -f "$DISK")
CONFIG_DATA=$(grep -vE '^\s*#' /etc/pve/qemu-server/*.conf /etc/pve/lxc/*.conf 2>/dev/null)
if grep -Fq "$REAL_PATH" <<< "$CONFIG_DATA"; then
USED_BY="$(translate "In use")"
else
@ -220,8 +284,15 @@ while read -r DISK; do
SHOW_DISK=false
fi
# Check if disk is already assigned to this CT using persistent paths
if pct config "$CTID" | grep -vE '^\s*#|^description:' | grep -q "$DISK"; then
SHOW_DISK=false
else
# Also check persistent paths
PERSISTENT_DISK=$(get_persistent_path "$DISK")
if [[ "$PERSISTENT_DISK" != "$DISK" ]] && pct config "$CTID" | grep -vE '^\s*#|^description:' | grep -q "$PERSISTENT_DISK"; then
SHOW_DISK=false
fi
fi
if $SHOW_DISK; then
@ -229,6 +300,7 @@ while read -r DISK; do
[[ "$IS_RAID" == true ]] && LABEL+=" ⚠ RAID"
[[ "$IS_LVM" == true ]] && LABEL+=" ⚠ LVM"
[[ "$IS_ZFS" == true ]] && LABEL+=" ⚠ ZFS"
DESCRIPTION=$(printf "%-30s %10s%s" "$MODEL" "$SIZE" "$LABEL")
FREE_DISKS+=("$DISK" "$DESCRIPTION" "OFF")
fi
@ -270,6 +342,7 @@ msg_info "$(translate "Processing selected disks...")"
for DISK in $SELECTED; do
DISK=$(echo "$DISK" | tr -d '"')
DISK_INFO=$(get_disk_info "$DISK")
ASSIGNED_TO=""
RUNNING_CTS=""
RUNNING_VMS=""
@ -309,6 +382,7 @@ for DISK in $SELECTED; do
fi
cleanup
if lsblk "$DISK" | grep -q "raid" || grep -q "${DISK##*/}" /proc/mdstat; then
whiptail --title "$(translate "RAID Detected")" --msgbox "$(translate "The disk") $DISK_INFO $(translate "appears to be part of a") RAID. $(translate "For security reasons, the system cannot format it.")\\n\\n$(translate "If you are sure you want to use it, please remove the") RAID metadata $(translate "or format it manually using external tools.")\\n\\n$(translate "After that, run this script again to add it.")" 18 70
clear
@ -350,12 +424,14 @@ for DISK in $SELECTED; do
if [ $? -ne 0 ]; then
continue
fi
echo -e "$(translate "Creating partition table and partition...")"
parted -s "$DISK" mklabel gpt
parted -s "$DISK" mkpart primary 0% 100%
sleep 2
partprobe "$DISK"
sleep 2
PARTITION=$(lsblk -rno NAME "$DISK" | awk -v disk="$(basename "$DISK")" '$1 != disk {print $1; exit}')
if [ -n "$PARTITION" ]; then
PARTITION="/dev/$PARTITION"
@ -383,7 +459,6 @@ for DISK in $SELECTED; do
fi
whiptail --title "$(translate "WARNING")" --yesno "$(translate "WARNING: This operation will FORMAT the disk") $DISK_INFO $(translate "with") $FORMAT_TYPE.\\n\\n$(translate "ALL DATA ON THIS DISK WILL BE PERMANENTLY LOST!")\\n\\n$(translate "Are you sure you want to continue")" 15 70
if [ $? -ne 0 ]; then
whiptail --title "$(translate "Format Cancelled")" --msgbox "$(translate "Format operation cancelled. The disk will not be added.")" 8 60
continue
@ -444,32 +519,38 @@ for DISK in $SELECTED; do
fi
##############################################################################
# Get persistent path for the partition
PERSISTENT_PARTITION=$(get_persistent_path "$PARTITION")
# Apply passthrough with persistent path
CURRENT_FS=$(lsblk -no FSTYPE "$PARTITION" | xargs)
if [ "$CURRENT_FS" == "xfs" ] || [ "$FORMAT_TYPE" == "xfs" ]; then
RESULT=$(pct set "$CTID" -mp${INDEX} "$PARTITION,mp=$MOUNT_POINT,backup=0,ro=0" 2>&1)
RESULT=$(pct set "$CTID" -mp${INDEX} "$PERSISTENT_PARTITION,mp=$MOUNT_POINT,backup=0,ro=0" 2>&1)
else
RESULT=$(pct set "$CTID" -mp${INDEX} "$PARTITION,mp=$MOUNT_POINT,backup=0,ro=0,acl=1" 2>&1)
RESULT=$(pct set "$CTID" -mp${INDEX} "$PERSISTENT_PARTITION,mp=$MOUNT_POINT,backup=0,ro=0,acl=1" 2>&1)
fi
# Adjust permissions inside the CT
pct exec "$CTID" -- chmod -R 775 "$MOUNT_POINT" 2>/dev/null || true
pct exec "$CTID" -- chmod -R 777 "$MOUNT_POINT" 2>/dev/null || true
# Show confirmation with persistent identifier
msg_ok "$(translate "Assigned using") $PERSISTENT_PARTITION"
##############################################################################
if [ $? -eq 0 ]; then
MESSAGE="$(translate "The disk") $DISK_INFO $(translate "has been successfully added to CT") $CTID $(translate "as a mount point at") $MOUNT_POINT."
MESSAGE+="\\n$(translate "Using persistent path"): $PERSISTENT_PARTITION"
if [ -n "$ASSIGNED_TO" ]; then
MESSAGE+="\\n\\n$(translate "WARNING: This disk is also assigned to the following CT(s):")\\n$ASSIGNED_TO"
MESSAGE+="\\n$(translate "Make sure not to start CTs that share this disk at the same time to avoid data corruption.")"
fi
SUCCESS_MESSAGES+="$MESSAGE\\n\\n"
((DISKS_ADDED++))
else
ERROR_MESSAGES+="$(translate "Could not add disk") $DISK_INFO $(translate "to CT") $CTID.\\n$(translate "Error:") $RESULT\\n\\n"
fi
done
msg_ok "$(translate "Disk processing completed.")"
@ -485,5 +566,4 @@ fi
msg_success "$(translate "Press Enter to return to menu...")"
read -r
exit 0

View File

@ -0,0 +1,267 @@
#!/bin/bash
# ==========================================================
# ProxMenu - Manual Proxmox VE 8 to 9 Upgrade Guide
# ==========================================================
# Author : MacRimi
# Copyright : (c) 2024 MacRimi
# License : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE)
# Version : 1.0
# Last Updated: 13/08/2025
# ==========================================================
# Configuration ============================================
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
VENV_PATH="/opt/googletrans-env"
if [[ -f "$UTILS_FILE" ]]; then
source "$UTILS_FILE"
fi
load_language
initialize_cache
# ==========================================================
show_command() {
local step="$1"
local description="$2"
local command="$3"
local note="$4"
local command_extra="$5"
echo -e "${BGN}${step}.${CL} ${BL}${description}${CL}"
echo ""
echo -e "${TAB}${command}"
echo -e
[[ -n "$note" ]] && echo -e "${TAB}${DARK_GRAY}${note}${CL}"
[[ -n "$command_extra" ]] && echo -e "${TAB}${YW}${command_extra}${CL}"
echo ""
}
show_proxmox_upgrade_manual_guide() {
clear
show_proxmenux_logo
msg_title "$(translate "Proxmox VE 8 to 9 Manual Upgrade Guide")"
echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}"
echo -e
echo -e "${TAB}${BGN}$(translate "Source:")${CL} ${BL}https://pve.proxmox.com/wiki/Upgrade_from_8_to_9${CL}"
echo -e
echo -e
echo -e "${TAB}${BOLD}$(translate "IMPORTANT PREREQUISITES:")${CL}"
echo -e
echo -e "${TAB}${BGN}$(translate "System must be updated to latest PVE 8.4+ before starting")${CL}"
echo -e "${TAB}${BGN}$(translate "Use SSH or terminal access (SSH recommended)")${CL}"
echo -e "${TAB}${BGN}$(translate "Use tmux or screen to avoid interruptions")${CL}"
echo -e "${TAB}${BGN}$(translate "Have valid backups of all VMs and containers")${CL}"
echo -e "${TAB}${BGN}$(translate "At least 5GB free space on root filesystem")${CL}"
echo -e "${TAB}${BGN}$(translate "Do not run the upgrade from the Web UI virtual console (it will disconnect)")${CL}"
echo -e
echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}"
echo -e
show_command "1" \
"$(translate "Update system to latest PVE 8.4+ (if not done already):")\n\n" \
"apt update && apt dist-upgrade -y" \
"$(translate "Or use ProxMenux update function")" \
"\n\n"
show_command "2" \
"$(translate "Verify PVE version (must be 8.4.1 or newer):")\n\n" \
"pveversion" \
"" \
"\n"
show_command "2.1" \
"${YW}$(translate "If this node runs hyper-converged Ceph: ensure Ceph is 19.x (Squid) BEFORE upgrading PVE.")${CL}\n\n" \
"ceph --version" \
"$(translate "If not 19.x, upgrade Ceph (Reef→Squid) first per the official guide:") ${BL}https://pve.proxmox.com/wiki/Ceph_Squid${CL}" \
"\n"
show_command "3" \
"$(translate "Run upgrade checklist script:")\n\n" \
"pve8to9 --full" \
"${YW}$(translate "If it warns about 'systemd-boot' meta-package, remove it:")${CL} apt remove systemd-boot" \
"\n"
show_command "4" \
"$(translate "Start terminal multiplexer (recommended):")\n\n" \
"tmux new-session -s upgrade ${DARK_GRAY}$(translate "# Recommended: avoids disconnection during upgrade")${CL}\n\n screen -S upgrade ${DARK_GRAY}$(translate "# Alternative if you prefer screen")${CL}" \
"" \
"\n"
show_command "5" \
"$(translate "Update Debian repositories to Trixie:")\n\n" \
"sed -i 's/bookworm/trixie/g' /etc/apt/sources.list" \
"" \
"\n"
show_command "6" \
"${YW}$(translate "Update PVE enterprise repository (Only if using enterprise):")${CL}\n\n" \
"${CUS}sed -i 's/bookworm/trixie/g' /etc/apt/sources.list.d/pve-enterprise.list${CL}" \
"$(translate "Skip this step if using no-subscription repository")" \
"\n\n"
show_command "7" \
"${YW}$(translate "Add new PVE 9 enterprise repository (deb822 format) (Only if using enterprise):")${CL}\n\n" \
"${CUS}cat > /etc/apt/sources.list.d/pve-enterprise.sources << EOF
Types: deb
URIs: https://enterprise.proxmox.com/debian/pve
Suites: trixie
Components: pve-enterprise
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF${CL}" \
"$(translate "Only if using enterprise subscription")" \
"\n\n"
show_command "8" \
"$(translate "OR add new PVE 9 no-subscription repository:")\n\n" \
"cat > /etc/apt/sources.list.d/proxmox.sources << EOF
Types: deb
URIs: http://download.proxmox.com/debian/pve
Suites: trixie
Components: pve-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF" \
"$(translate "Only if using no-subscription repository")" \
"\n\n"
show_command "8.1" \
"$(translate "Refresh APT index and verify repositories:")\n\n" \
"apt update && apt policy | sed -n '1,120p'" \
"$(translate "Ensure there are no errors and that proxmox-ve candidate shows 9.x")" \
"\n"
show_command "9" \
"${YW}$(translate "Update Ceph repository (Only if using Ceph):")${CL}\n\n" \
"${CUS}cat > /etc/apt/sources.list.d/ceph.sources << EOF
Types: deb
URIs: http://download.proxmox.com/debian/ceph-squid
Suites: trixie
Components: no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF${CL}" \
"$(translate "Use enterprise URL if you have subscription.")" \
"\n\n"
show_command "10" \
"$(translate "Remove old repository files:")\n\n" \
"rm -f /etc/apt/sources.list.d/pve-enterprise.list /etc/apt/sources.list.d/ceph.list" \
"$(translate "Also comment any remaining 'bookworm' entries in *.list if present.")" \
"\n"
show_command "11" \
"$(translate "Update package index:")\n\n" \
"apt update" \
"" \
"\n"
show_command "12" \
"$(translate "Disable kernel audit messages (optional but recommended):")\n\n" \
"systemctl disable --now systemd-journald-audit.socket" \
"" \
"\n"
show_command "13" \
"$(translate "Start the main system upgrade:")\n\n" \
"apt dist-upgrade" \
"$(translate "This will take time. Answer prompts carefully - see notes below.")\n" \
"\n"
echo -e "${TAB}${BOLD}$(translate "UPGRADE PROMPTS - RECOMMENDED ANSWERS:")${CL}"
echo -e
echo -e "${TAB}${BGN}/etc/issue:${CL} ${YW}$(translate "Keep current version (N)")${CL}"
echo -e "${TAB}${BGN}/etc/lvm/lvm.conf:${CL} ${YW}$(translate "Install maintainer's version (Y)")${CL}"
echo -e "${TAB}${BGN}/etc/ssh/sshd_config:${CL} ${YW}$(translate "Install maintainer's version (Y)")${CL}"
echo -e "${TAB}${BGN}/etc/default/grub:${CL} ${YW}$(translate "Keep current version (N) if modified")${CL}"
echo -e "${TAB}${BGN}/etc/chrony/chrony.conf:${CL} ${YW}$(translate "Install maintainer's version (Y)")${CL}"
echo -e "${TAB}${BGN}$(translate "Service restarts:")${CL} ${YW}$(translate "Use default (Yes)")${CL}"
echo -e "${TAB}${BGN}apt-listchanges:${CL} ${YW}$(translate "Press 'q' to exit")${CL}"
echo -e
echo -e
echo -e
show_command "13.1" \
"${YW}$(translate "If booting in EFI mode with root on LVM: install GRUB for EFI")${CL}\n\n" \
"[ -d /sys/firmware/efi ] && apt install grub-efi-amd64" \
"$(translate "Per official known issues; ensures proper boot after upgrade")" \
"\n"
show_command "14" \
"$(translate "Run checklist again to verify upgrade:")\n\n" \
"pve8to9 --full" \
"$(translate "Should show fewer or no issues")" \
"\n"
show_command "15" \
"$(translate "Reboot the system:")\n\n" \
"reboot" \
"" \
"\n"
show_command "16" \
"$(translate "After reboot, verify PVE version:")\n\n" \
"pveversion" \
"$(translate "Should show pve-manager/9.x.x")" \
"\n"
show_command "17" \
"$(translate "Optional: Modernize repository sources:")\n\n" \
"apt modernize-sources" \
"$(translate "Converts to deb822; keeps .list backups as .bak")" \
"\n"
echo -e "${TAB}${BL}------------------------------------------------------------------------${CL}"
echo -e
echo -e
echo -e "${TAB}${BOLD}$(translate "CLUSTER UPGRADE NOTES:")${CL}"
echo -e
echo -e "${TAB}${BGN}$(translate "Upgrade one node at a time")${CL}"
echo -e "${TAB}${BGN}$(translate "Migrate VMs away from node being upgraded")${CL}"
echo -e "${TAB}${BGN}$(translate "Wait for each node to complete before starting next")${CL}"
echo -e "${TAB}${BGN}$(translate "HA groups will be migrated to HA rules automatically")${CL}"
echo -e
echo -e
echo -e
echo -e "${TAB}${BOLD}$(translate "TROUBLESHOOTING:")${CL}"
echo -e
echo -e "${TAB}${BGN}$(translate "If upgrade fails:")${CL} ${YW}apt -f install${CL}"
echo -e "${TAB}${BGN}$(translate "If repositories error:")${CL} ${YW}Check /etc/apt/sources.list*${CL}"
echo -e "${TAB}${BGN}$(translate "If 'proxmox-ve' removal warning:")${CL} ${YW}Fix repository configuration (ensure PVE 9 repo active)${CL}"
echo -e "${TAB}${BGN}$(translate "Emergency recovery:")${CL} ${YW}Boot from rescue system${CL}"
echo -e
echo -e
echo -e
msg_success "$(translate "Press Enter to return to menu...")"
echo -e
read -r
}
# Main execution
show_proxmox_upgrade_manual_guide

View File

@ -41,464 +41,91 @@ initialize_cache
# ==========================================================
OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs )"
if [ -z "$OS_CODENAME" ]; then
OS_CODENAME=$(lsb_release -cs 2>/dev/null || echo "bookworm")
fi
# ======================================================
# Auxiliary functions
# ======================================================
lvm_repair_check() {
msg_info "$(translate "Checking and repairing old LVM PV headers (if needed)...")"
pvs_output=$(LC_ALL=C pvs -v 2>&1 | grep "old PV header")
if [ -z "$pvs_output" ]; then
msg_ok "$(translate "No PVs with old headers found.")"
return
fi
declare -A vg_map
while read -r line; do
pv=$(echo "$line" | grep -o '/dev/[^ ]*')
vg=$(pvs -o vg_name --noheadings "$pv" | awk '{print $1}')
if [ -n "$vg" ]; then
vg_map["$vg"]=1
fi
done <<< "$pvs_output"
for vg in "${!vg_map[@]}"; do
msg_warn "$(translate "Old PV header(s) found in VG $vg. Updating metadata...")"
vgck --updatemetadata "$vg"
vgchange -ay "$vg"
if [ $? -ne 0 ]; then
msg_warn "$(translate "Metadata update failed for VG $vg. Review manually.")"
else
msg_ok "$(translate "Metadata updated successfully for VG $vg")"
fi
done
}
cleanup_duplicate_repos() {
local sources_file="/etc/apt/sources.list"
local temp_file=$(mktemp)
local cleaned_count=0
declare -A seen_repos
while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "$line" ]]; then
echo "$line" >> "$temp_file"
continue
fi
if [[ "$line" =~ ^deb ]]; then
read -r _ url dist components <<< "$line"
local key="${url}_${dist}"
if [[ -v "seen_repos[$key]" ]]; then
echo "# $line" >> "$temp_file"
cleaned_count=$((cleaned_count + 1))
else
echo "$line" >> "$temp_file"
seen_repos[$key]="$components"
fi
else
echo "$line" >> "$temp_file"
fi
done < "$sources_file"
mv "$temp_file" "$sources_file"
chmod 644 "$sources_file"
local pve_files=(/etc/apt/sources.list.d/*proxmox*.list /etc/apt/sources.list.d/*pve*.list)
local pve_public_repo="/etc/apt/sources.list.d/pve-public-repo.list"
local pve_public_repo_exists=false
local pve_repo_count=0
if [ -f "$pve_public_repo" ] && grep -q "^deb.*pve-no-subscription" "$pve_public_repo"; then
pve_public_repo_exists=true
pve_repo_count=1
fi
for file in "${pve_files[@]}"; do
if [ -f "$file" ] && grep -q "^deb.*pve-no-subscription" "$file"; then
if ! $pve_public_repo_exists && [[ "$file" == "$pve_public_repo" ]]; then
sed -i 's/^# *deb/deb/' "$file"
pve_public_repo_exists=true
pve_repo_count=1
elif [[ "$file" != "$pve_public_repo" ]]; then
sed -i 's/^deb/# deb/' "$file"
cleaned_count=$((cleaned_count + 1))
fi
fi
done
if [ $cleaned_count -gt 0 ]; then
msg_ok "$(translate "Duplicate repositories cleaned: $cleaned_count")"
fi
apt update
}
NECESSARY_REBOOT=1
apt_upgrade() {
local start_time=$(date +%s)
local log_file="/var/log/proxmox-update-$(date +%Y%m%d-%H%M%S).log"
local changes_made=false
local pve_version
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+' | head -1)
clear
show_proxmenux_logo
echo -e
msg_title "$(translate "Proxmox system update")"
# ======================================================
# Basic checks
# ======================================================
# Check minimum disk space
local available_space=$(df /var/cache/apt/archives | awk 'NR==2 {print int($4/1024)}')
if [ "$available_space" -lt 1024 ]; then
msg_error "$(translate "Insufficient disk space. Available: ${available_space}MB")"
if [[ -z "$pve_version" ]]; then
msg_error "Unable to detect Proxmox version."
return 1
fi
# Check connectivity
if ! ping -c 1 download.proxmox.com >/dev/null 2>&1; then
msg_error "$(translate "Cannot reach Proxmox repositories")"
return 1
fi
if [[ "$pve_version" -ge 9 ]]; then
show_proxmenux_logo
msg_title "$(translate "Proxmox system update")"
bash <(curl -fsSL "$REPO_URL/scripts/global/update-pve.sh")
# ======================================================
# Proxmox repository configuration
# ======================================================
# Disable enterprise Proxmox repository
if [ -f /etc/apt/sources.list.d/pve-enterprise.list ] && grep -q "^deb" /etc/apt/sources.list.d/pve-enterprise.list; then
msg_info "$(translate "Disabling enterprise Proxmox repository...")"
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/pve-enterprise.list
msg_ok "$(translate "Enterprise Proxmox repository disabled")"
changes_made=true
fi
# Disable enterprise Ceph repository
if [ -f /etc/apt/sources.list.d/ceph.list ] && grep -q "^deb" /etc/apt/sources.list.d/ceph.list; then
msg_info "$(translate "Disabling enterprise Ceph repository...")"
sed -i "s/^deb/#deb/g" /etc/apt/sources.list.d/ceph.list
msg_ok "$(translate "Enterprise Ceph repository disabled")"
changes_made=true
fi
# Enable free public repository
if [ ! -f /etc/apt/sources.list.d/pve-public-repo.list ] || ! grep -q "pve-no-subscription" /etc/apt/sources.list.d/pve-public-repo.list; then
msg_info "$(translate "Enabling free public Proxmox repository...")"
echo "deb http://download.proxmox.com/debian/pve ${OS_CODENAME} pve-no-subscription" > /etc/apt/sources.list.d/pve-public-repo.list
msg_ok "$(translate "Free public Proxmox repository enabled")"
changes_made=true
fi
# ======================================================
# Debian repository configuration
# ======================================================
local sources_file="/etc/apt/sources.list"
local debian_changes=false
# Clean up malformed entries first
if grep -q -E "(debian-security -security|debian main$|debian -updates)" "$sources_file"; then
msg_info "$(translate "Cleaning malformed repository entries...")"
# Remove malformed lines that cause 404 errors
sed -i '/^deb.*debian-security -security/d' "$sources_file"
sed -i '/^deb.*debian main$/d' "$sources_file"
sed -i '/^deb.*debian -updates/d' "$sources_file"
debian_changes=true
msg_ok "$(translate "Cleaning malformed repository sucefull")"
fi
# Replace old mirrors
if grep -q "ftp.es.debian.org" "$sources_file"; then
sed -i 's|ftp.es.debian.org|deb.debian.org|g' "$sources_file"
debian_changes=true
fi
# Fix incomplete security repository line
if grep -q "^deb http://security.debian.org ${OS_CODENAME}-security main contrib$" "$sources_file"; then
sed -i "s|^deb http://security.debian.org ${OS_CODENAME}-security main contrib$|deb http://security.debian.org/debian-security ${OS_CODENAME}-security main contrib non-free non-free-firmware|" "$sources_file"
debian_changes=true
fi
local temp_sources=$(mktemp)
grep -E '^[[:space:]]*#|^[[:space:]]*$' "$sources_file" > "$temp_sources"
cat >> "$temp_sources" << EOF
# Debian ${OS_CODENAME} repositories
deb http://deb.debian.org/debian ${OS_CODENAME} main contrib non-free non-free-firmware
deb http://deb.debian.org/debian ${OS_CODENAME}-updates main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security ${OS_CODENAME}-security main contrib non-free non-free-firmware
EOF
if ! cmp -s "$sources_file" "$temp_sources"; then
cp "$sources_file" "${sources_file}.backup-$(date +%Y%m%d-%H%M%S)"
mv "$temp_sources" "$sources_file"
debian_changes=true
msg_ok "$(translate "Debian repositories updated")"
else
rm "$temp_sources"
show_proxmenux_logo
msg_title "$(translate "Proxmox system update")"
bash <(curl -fsSL "$REPO_URL/scripts/global/update-pve8.sh")
fi
if [ ! -f /etc/apt/apt.conf.d/no-bookworm-firmware.conf ]; then
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' > /etc/apt/apt.conf.d/no-bookworm-firmware.conf
debian_changes=true
fi
if [ "$debian_changes" = true ]; then
changes_made=true
fi
# ======================================================
# Clean duplicate repositories
# ======================================================
cleanup_duplicate_repos
# ======================================================
# System update
# ======================================================
# Update package lists
if [ "$changes_made" = true ]; then
msg_info "$(translate "Updating package lists...")"
else
msg_info "$(translate "Checking for available updates...")"
fi
if apt-get update > "$log_file" 2>&1; then
msg_ok "$(translate "Package lists updated")"
else
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
echo "$(translate "Repository errors found:")"
grep -E "Err:|E:" "$log_file" | head -5
return 1
fi
# Remove conflicting packages
local conflicting_packages=$(dpkg -l 2>/dev/null | grep -E "^ii.*(ntp|openntpd|systemd-timesyncd)" | awk '{print $2}')
if [ -n "$conflicting_packages" ]; then
msg_info "$(translate "Removing conflicting packages...")"
DEBIAN_FRONTEND=noninteractive apt-get -y purge $conflicting_packages >> "$log_file" 2>&1
msg_ok "$(translate "Conflicting packages removed")"
fi
# Show update information
local upgradable=$(apt list --upgradable 2>/dev/null | grep -c "upgradable")
if [ "$upgradable" -gt 0 ]; then
# Show with dialog if available
if command -v whiptail >/dev/null 2>&1; then
if whiptail --title "$(translate "Proxmox Update")" \
--yesno "$(translate "Found $upgradable packages to upgrade.\n\nProceed with system update?")" 10 60; then
msg_info "$(translate "Performing system upgrade. This process may take several minutes...")"
else
msg_info2 "$(translate "Update cancelled by user")"
return 0
fi
fi
else
msg_success "$(translate "System is already up to date")"
echo -e
msg_success "$(translate "Press Enter to return to menu...")"
read -r
return 0
fi
# Perform update
# msg_info "$(translate "Performing system upgrade...")"
# echo "$(translate "This process may take several minutes...")"
# Update with logging
if DEBIAN_FRONTEND=noninteractive apt-get -y \
-o Dpkg::Options::='--force-confdef' \
-o Dpkg::Options::='--force-confold' \
dist-upgrade >> "$log_file" 2>&1; then
msg_ok "$(translate "System upgrade completed successfully")"
else
msg_error "$(translate "System upgrade failed. Check log: $log_file")"
return 1
fi
# Install essential Proxmox packages if missing
local essential_packages=("zfsutils-linux" "proxmox-backup-restore-image" "chrony")
local missing_packages=()
for package in "${essential_packages[@]}"; do
if ! dpkg -l 2>/dev/null | grep -q "^ii $package "; then
missing_packages+=("$package")
fi
done
if [ ${#missing_packages[@]} -gt 0 ]; then
msg_info "$(translate "Installing essential Proxmox packages...")"
DEBIAN_FRONTEND=noninteractive apt-get -y install "${missing_packages[@]}" >> "$log_file" 2>&1
msg_ok "$(translate "Essential Proxmox packages installed")"
fi
# Check LVM
lvm_repair_check
# ======================================================
# Final summary - BEFORE reboot logic
# ======================================================
local end_time=$(date +%s)
local duration=$((end_time - start_time))
local minutes=$((duration / 60))
local seconds=$((duration % 60))
echo ""
echo "$(translate "=== UPDATE COMPLETED ===")"
echo "$(translate "Duration"): ${minutes}m ${seconds}s"
echo "$(translate "Log file"): $log_file"
echo "$(translate "Packages upgraded"): $upgradable"
echo ""
msg_success "$(translate "Proxmox system update completed successfully")"
}
# ======================================================
# Reboot logic - After summary
# ======================================================
# Check if reboot is needed (kernel updates, system packages, etc.)
check_reboot() {
NECESSARY_REBOOT=0
# Check for reboot-required file
if [ -f /var/run/reboot-required ]; then
NECESSARY_REBOOT=1
fi
# Check if kernel was updated
if grep -q "linux-image" "$log_file" 2>/dev/null; then
NECESSARY_REBOOT=1
fi
# For system updates, it's generally safer to reboot
if [ "$upgradable" -gt 0 ]; then
NECESSARY_REBOOT=1
fi
if [[ "$NECESSARY_REBOOT" -eq 1 ]]; then
if command -v whiptail >/dev/null 2>&1; then
if whiptail --title "$(translate "Reboot Required")" \
--yesno "$(translate "Some changes require a reboot to take effect. Do you want to restart now?")" 10 60; then
if whiptail --title "$(translate "Reboot Required")" \
--yesno "$(translate "Some changes require a reboot to take effect. Do you want to restart now?")" 10 60; then
msg_info "$(translate "Removing no longer required packages and purging old cached updates...")"
apt-get -y autoremove >/dev/null 2>&1
apt-get -y autoclean >/dev/null 2>&1
msg_ok "$(translate "Cleanup finished")"
msg_info "$(translate "Removing no longer required packages and purging old cached updates...")"
apt-get -y autoremove >/dev/null 2>&1
apt-get -y autoclean >/dev/null 2>&1
msg_ok "$(translate "Cleanup finished")"
echo -e
msg_success "$(translate "Press Enter to continue...")"
read -r
msg_success "$(translate "Press Enter to continue...")"
read -r
msg_warn "$(translate "Rebooting the system...")"
reboot
else
msg_info "$(translate "Removing no longer required packages and purging old cached updates...")"
apt-get -y autoremove >/dev/null 2>&1
apt-get -y autoclean >/dev/null 2>&1
msg_ok "$(translate "Cleanup finished")"
msg_info2 "$(translate "You can reboot later manually.")"
msg_success "$(translate "Press Enter to continue...")"
read -r
return 0
fi
msg_warn "$(translate "Rebooting the system...")"
reboot
else
# Fallback without whiptail
echo "$(translate "Reboot now? (y/N): ")"
read -r -t 30 response
if [[ "$response" =~ ^[Yy]$ ]]; then
msg_info "$(translate "Removing no longer required packages and purging old cached updates...")"
apt-get -y autoremove >/dev/null 2>&1
apt-get -y autoclean >/dev/null 2>&1
msg_ok "$(translate "Cleanup finished")"
msg_warn "$(translate "Rebooting the system...")"
sleep 3
reboot
else
msg_info "$(translate "Removing no longer required packages and purging old cached updates...")"
apt-get -y autoremove >/dev/null 2>&1
apt-get -y autoclean >/dev/null 2>&1
msg_ok "$(translate "Cleanup finished")"
msg_info2 "$(translate "You can reboot later manually.")"
return 0
fi
msg_info "$(translate "Removing no longer required packages and purging old cached updates...")"
apt-get -y autoremove >/dev/null 2>&1
apt-get -y autoclean >/dev/null 2>&1
msg_ok "$(translate "Cleanup finished")"
echo -e
msg_info2 "$(translate "You can reboot later manually.")"
echo -e
msg_success "$(translate "Press Enter to continue...")"
read -r
return 0
fi
else
msg_info "$(translate "Removing no longer required packages and purging old cached updates...")"
apt-get -y autoremove >/dev/null 2>&1
apt-get -y autoclean >/dev/null 2>&1
msg_ok "$(translate "Cleanup finished")"
msg_success "$(translate "All changes applied. No reboot required.")"
echo -e
msg_ok "$(translate "All changes applied. No reboot required.")"
echo -e
msg_success "$(translate "Press Enter to return to menu...")"
read -r
fi
return 0
}
# Function to show available update information
check_updates_available() {
msg_info "$(translate "Checking for available updates...")"
apt-get update >/dev/null 2>&1
local upgradable=$(apt list --upgradable 2>/dev/null | grep -c "upgradable")
local security_updates=$(apt list --upgradable 2>/dev/null | grep -c "security")
if [ "$upgradable" -gt 0 ]; then
echo "$(translate "Updates available"): $upgradable"
echo "$(translate "Security updates"): $security_updates"
cleanup
if command -v whiptail >/dev/null 2>&1; then
whiptail --title "$(translate "Updates Available")" \
--msgbox "$(translate "Updates available: $upgradable\nSecurity updates: $security_updates\n\nUse the update option to proceed.")" 12 60
fi
else
msg_ok "$(translate "System is up to date")"
fi
}
apt_upgrade
check_reboot
# Execute function based on parameter
case "${1:-}" in
"check")
check_updates_available
;;
"")
apt_upgrade
;;
*)
echo "$(translate "Usage: $0 [check]")"
echo "$(translate " check - Check for available updates")"
echo "$(translate " (no args) - Perform full system update")"
;;
esac

View File

@ -1,13 +1,12 @@
#!/bin/bash
# ==========================================================
# ProxMenux - A menu-driven script for Proxmox VE management
# ==========================================================
# Author : MacRimi
# Copyright : (c) 2024 MacRimi
# License : MIT (https://raw.githubusercontent.com/MacRimi/ProxMenux/main/LICENSE)
# Version : 1.0
# Last Updated: 30/06/2025
# Version : 1.1
# Last Updated: 30/07/2025
# ==========================================================
# Description:
# This script provides an interactive system utilities installer with a
@ -34,8 +33,8 @@
# It includes built-in troubleshooting for common PATH and command availability
# issues that may occur after package installation.
#
# Configuration ============================================
# Configuration ============================================
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
@ -44,66 +43,64 @@ VENV_PATH="/opt/googletrans-env"
if [[ -f "$UTILS_FILE" ]]; then
source "$UTILS_FILE"
fi
load_language
initialize_cache
OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs )"
# ==========================================================
install_system_utils() {
command_exists() {
command -v "$1" >/dev/null 2>&1
}
ensure_repositories() {
local sources_file="/etc/apt/sources.list"
local need_update=false
if [[ ! -f "$sources_file" ]]; then
msg_warn "$(translate "sources.list not found, creating default Debian repository...")"
cat > "$sources_file" << EOF
# Default Debian ${OS_CODENAME} repository
deb http://deb.debian.org/debian ${OS_CODENAME} main contrib non-free non-free-firmware
EOF
need_update=true
else
if ! grep -q "deb.*${OS_CODENAME}.*main" "$sources_file"; then
echo "deb http://deb.debian.org/debian ${OS_CODENAME} main contrib non-free non-free-firmware" >> "$sources_file"
need_update=true
fi
fi
if [[ "$need_update" == true ]] || ! apt list --installed >/dev/null 2>&1; then
msg_info "$(translate "Updating APT package lists...")"
apt-get update -o Acquire::AllowInsecureRepositories=true >/dev/null 2>&1
fi
return 0
}
install_single_package() {
local package="$1"
local command_name="${2:-$package}"
local description="$3"
msg_info "$(translate "Installing") $package ($description)..."
local install_success=false
if command_exists apt; then
if apt update >/dev/null 2>&1 && apt install -y "$package" >/dev/null 2>&1; then
install_success=true
fi
elif command_exists yum; then
if yum install -y "$package" >/dev/null 2>&1; then
install_success=true
fi
elif command_exists dnf; then
if dnf install -y "$package" >/dev/null 2>&1; then
install_success=true
fi
elif command_exists pacman; then
if pacman -S --noconfirm "$package" >/dev/null 2>&1; then
install_success=true
fi
elif command_exists zypper; then
if zypper install -y "$package" >/dev/null 2>&1; then
install_success=true
fi
else
cleanup
msg_error "$(translate "No compatible package manager detected")"
return 1
if apt install -y "$package" >/dev/null 2>&1; then
install_success=true
fi
cleanup
if [ "$install_success" = true ]; then
hash -r 2>/dev/null
sleep 1
if command_exists "$command_name"; then
msg_ok "$package $(translate "installed correctly and available")"
return 0
@ -118,27 +115,25 @@ install_system_utils() {
fi
}
show_main_utilities_menu() {
local choice
choice=$(dialog --clear --backtitle "ProxMenux" \
--title "$(translate "Utilities Installation Menu")" \
--menu "$(translate "Select an option"):" 20 70 12 \
"1" "$(translate "Custom selection")" \
"2" "$(translate "Install ALL utilities")" \
"3" "$(translate "Install basic utilities") (grc, htop, tree, curl, wget)" \
"4" "$(translate "Install development tools") (git, vim, nano)" \
"5" "$(translate "Install compression tools") (zip, unzip, rsync)" \
"6" "$(translate "Install terminal multiplexers") (screen, tmux)" \
"7" "$(translate "Install analysis tools") (jq, ncdu, iotop)" \
"8" "$(translate "Install network tools") (nethogs, nmap, tcpdump, lsof)" \
"9" "$(translate "Verify installations")" \
"0" "$(translate "Return to main menu")" 2>&1 >/dev/tty)
--title "$(translate "Utilities Installation Menu")" \
--menu "$(translate "Select an option"):" 20 70 12 \
"1" "$(translate "Custom selection")" \
"2" "$(translate "Install ALL utilities")" \
"3" "$(translate "Install basic utilities") (grc, htop, tree, curl, wget)" \
"4" "$(translate "Install development tools") (git, vim, nano)" \
"5" "$(translate "Install compression tools") (zip, unzip, rsync)" \
"6" "$(translate "Install terminal multiplexers") (screen, tmux)" \
"7" "$(translate "Install analysis tools") (jq, ncdu, iotop)" \
"8" "$(translate "Install network tools") (nethogs, nmap, tcpdump, lsof)" \
"9" "$(translate "Verify installations")" \
"0" "$(translate "Return to main menu")" 2>&1 >/dev/tty)
echo "$choice"
}
show_custom_selection() {
local utilities=(
"axel" "$(translate "Download accelerator")" "OFF"
@ -168,14 +163,13 @@ install_system_utils() {
local selected
selected=$(dialog --clear --backtitle "ProxMenux" \
--title "$(translate "Select utilities to install")" \
--checklist "$(translate "Use SPACE to select/deselect, ENTER to confirm")" \
25 80 20 "${utilities[@]}" 2>&1 >/dev/tty)
--title "$(translate "Select utilities to install")" \
--checklist "$(translate "Use SPACE to select/deselect, ENTER to confirm")" \
25 80 20 "${utilities[@]}" 2>&1 >/dev/tty)
echo "$selected"
}
install_utility_group() {
local group_name="$1"
shift
@ -185,11 +179,16 @@ install_system_utils() {
show_proxmenux_logo
msg_title "$(translate "Installing group"): $group_name"
if ! ensure_repositories; then
msg_error "$(translate "Failed to configure repositories. Installation aborted.")"
return 1
fi
local failed=0
local success=0
local warning=0
declare -A package_to_command=(
["mlocate"]="locate"
["msr-tools"]="rdmsr"
@ -201,11 +200,7 @@ install_system_utils() {
for util_info in "${utilities[@]}"; do
IFS=':' read -r package command description <<< "$util_info"
local verify_command="${package_to_command[$package]:-$command}"
install_single_package "$package" "$verify_command" "$description"
local install_result=$?
@ -214,6 +209,7 @@ install_system_utils() {
1) failed=$((failed + 1)) ;;
2) warning=$((warning + 1)) ;;
esac
sleep 2
done
echo
@ -223,18 +219,17 @@ install_system_utils() {
[ $failed -gt 0 ] && msg_error "$(translate "Failed"): $failed"
dialog --clear --backtitle "ProxMenux" \
--title "$(translate "Installation Complete")" \
--msgbox "$(translate "Group"): $group_name\n$(translate "Successful"): $success\n$(translate "With warnings"): $warning\n$(translate "Failed"): $failed" 10 50
--title "$(translate "Installation Complete")" \
--msgbox "$(translate "Group"): $group_name\n$(translate "Successful"): $success\n$(translate "With warnings"): $warning\n$(translate "Failed"): $failed" 10 50
}
install_selected_utilities() {
local selected="$1"
if [ -z "$selected" ]; then
dialog --clear --backtitle "ProxMenux" \
--title "$(translate "No Selection")" \
--msgbox "$(translate "No utilities were selected")" 8 40
--title "$(translate "No Selection")" \
--msgbox "$(translate "No utilities were selected")" 8 40
return
fi
@ -242,15 +237,18 @@ install_system_utils() {
show_proxmenux_logo
msg_title "$(translate "Installing selected utilities")"
if ! ensure_repositories; then
msg_error "$(translate "Failed to configure repositories. Installation aborted.")"
return 1
fi
local failed=0
local success=0
local warning=0
local selected_array
IFS=' ' read -ra selected_array <<< "$selected"
declare -A package_to_command=(
["mlocate"]="locate"
["msr-tools"]="rdmsr"
@ -261,13 +259,8 @@ install_system_utils() {
)
for util in "${selected_array[@]}"; do
util=$(echo "$util" | tr -d '"')
local verify_command="${package_to_command[$util]:-$util}"
install_single_package "$util" "$verify_command" "$util"
local install_result=$?
@ -276,14 +269,14 @@ install_system_utils() {
1) failed=$((failed + 1)) ;;
2) warning=$((warning + 1)) ;;
esac
sleep 2
done
if [ -f ~/.bashrc ]; then
source ~/.bashrc >/dev/null 2>&1
fi
hash -r 2>/dev/null
hash -r 2>/dev/null
echo
msg_info2 "$(translate "Installation summary"):"
msg_ok "$(translate "Successful"): $success"
@ -291,11 +284,10 @@ install_system_utils() {
[ $failed -gt 0 ] && msg_error "$(translate "Failed"): $failed"
dialog --clear --backtitle "ProxMenux" \
--title "$(translate "Installation Complete")" \
--msgbox "$(translate "Selected utilities installation completed")\n$(translate "Successful"): $success\n$(translate "With warnings"): $warning\n$(translate "Failed"): $failed" 12 60
--title "$(translate "Installation Complete")" \
--msgbox "$(translate "Selected utilities installation completed")\n$(translate "Successful"): $success\n$(translate "With warnings"): $warning\n$(translate "Failed"): $failed" 12 60
}
verify_installations() {
clear
show_proxmenux_logo
@ -348,24 +340,19 @@ install_system_utils() {
local summary="$(translate "Total"): $((available + missing))\n$(translate "Available"): $available\n$(translate "Missing"): $missing"
dialog --clear --backtitle "ProxMenux" \
--title "$(translate "Utilities Verification")" \
--msgbox "$summary$status_text" 25 80
--title "$(translate "Utilities Verification")" \
--msgbox "$summary$status_text" 25 80
}
# Main menu loop
while true; do
choice=$(show_main_utilities_menu)
case $choice in
1)
selected=$(show_custom_selection)
install_selected_utilities "$selected"
;;
2)
all_utils=(
"axel:axel:Download accelerator"
"dos2unix:dos2unix:Convert DOS/Unix text files"
@ -394,7 +381,6 @@ install_system_utils() {
install_utility_group "$(translate "ALL Utilities")" "${all_utils[@]}"
;;
3)
basic_utils=(
"grc:grc:Generic Colouriser"
"htop:htop:Process monitor"
@ -405,7 +391,6 @@ install_system_utils() {
install_utility_group "$(translate "Basic Utilities")" "${basic_utils[@]}"
;;
4)
dev_utils=(
"git:git:Version control"
"vim:vim:Advanced editor"
@ -414,7 +399,6 @@ install_system_utils() {
install_utility_group "$(translate "Development Tools")" "${dev_utils[@]}"
;;
5)
compress_utils=(
"zip:zip:ZIP compressor"
"unzip:unzip:ZIP extractor"
@ -423,7 +407,6 @@ install_system_utils() {
install_utility_group "$(translate "Compression Tools")" "${compress_utils[@]}"
;;
6)
multiplex_utils=(
"screen:screen:Terminal multiplexer"
"tmux:tmux:Advanced multiplexer"
@ -431,7 +414,6 @@ install_system_utils() {
install_utility_group "$(translate "Terminal Multiplexers")" "${multiplex_utils[@]}"
;;
7)
analysis_utils=(
"jq:jq:JSON processor"
"ncdu:ncdu:Disk analyzer"
@ -440,7 +422,6 @@ install_system_utils() {
install_utility_group "$(translate "Analysis Tools")" "${analysis_utils[@]}"
;;
8)
network_utils=(
"nethogs:nethogs:Network monitor"
"nmap:nmap:Network scanner"
@ -457,8 +438,8 @@ install_system_utils() {
;;
*)
dialog --clear --backtitle "ProxMenux" \
--title "$(translate "Invalid Option")" \
--msgbox "$(translate "Please select a valid option")" 8 40
--title "$(translate "Invalid Option")" \
--msgbox "$(translate "Please select a valid option")" 8 40
;;
esac
done
@ -466,5 +447,4 @@ install_system_utils() {
clear
}
install_system_utils

View File

@ -52,8 +52,7 @@ NEON_PURPLE_BLUE="\033[38;5;99m"
WHITE="\033[38;5;15m"
RESET="\033[0m"
DARK_GRAY="\033[38;5;244m"
DARK_GRAY="\033[38;5;244m"
DARK_GRAY="\033[38;5;244m"
ORANGE="\033[38;5;208m"
YW="\033[33m"
YWB="\033[1;33m"
GN="\033[1;92m"
@ -137,6 +136,12 @@ msg_info2() {
echo -e "${TAB}${BOLD}${YW}${HOLD}${msg}${CL}"
}
# Display info message with spinner
msg_info3() {
local msg="$1"
echo -ne "${TAB}${YW}${HOLD}${msg}${CL}"
}
# Display success message
msg_success() {
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID > /dev/null; then
@ -165,7 +170,7 @@ msg_warn() {
fi
printf "\e[?25h"
local msg="$1"
echo -e "${BFR}${TAB}${NV}${CL} ${YWB}${msg}${CL}"
echo -e "${BFR}${TAB}${CL} ${YWB}${msg}${CL}"
}
@ -179,6 +184,12 @@ msg_ok() {
echo -e "${BFR}${TAB}${CM}${GN}${msg}${CL}"
}
msg_ok2() {
printf "\e[?25h"
local msg="$1"
echo -e "${BFR}${TAB}${CM}${GN}${msg}${CL}"
}
# Display error message
msg_error() {
@ -249,21 +260,23 @@ translate() {
from googletrans import Translator
import sys, json, re
def translate_text(text, dest_lang):
def translate_text(text, dest_lang, context):
translator = Translator()
context = '$TRANSLATION_CONTEXT'
try:
full_text = context + ' ' + text
result = translator.translate(full_text, dest=dest_lang).text
# Remove context and any leading/trailing whitespace
translated = re.sub(r'^.*?(Translate:|Traducir:|Traduire:|Übersetzen:|Tradurre:|Traduzir:|翻译:|翻訳:)', '', result, flags=re.IGNORECASE | re.DOTALL).strip()
translated = re.sub(r'^.*?(Context:|Contexto:|Contexte:|Kontext:|Contesto:|上下文:|コンテキスト:).*?:', '', translated, flags=re.IGNORECASE | re.DOTALL).strip()
return json.dumps({'success': True, 'text': translated})
print(json.dumps({'success': True, 'text': translated}))
except Exception as e:
return json.dumps({'success': False, 'error': str(e)})
print(json.dumps({'success': False, 'error': str(e)}))
print(translate_text('$text', '$dest_lang'))
")
translate_text(
json.loads(sys.argv[1]),
sys.argv[2],
json.loads(sys.argv[3])
)
" "$(jq -Rn --arg t "$text" '$t')" "$dest_lang" "$(jq -Rn --arg ctx "$TRANSLATION_CONTEXT" '$ctx')")
deactivate
local translation_result=$(echo "$translated" | jq -r '.')

View File

@ -114,6 +114,7 @@ function select_linux_iso_official() {
"Debian 12 Netinst|CLI|ProxMenux|https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.10.0-amd64-netinst.iso"
"Debian 11 Netinst|CLI|ProxMenux|https://cdimage.debian.org/cdimage/archive/11.11.0/amd64/iso-cd/debian-11.11.0-amd64-netinst.iso"
"Fedora Workstation 42|Desktop|ProxMenux|https://download.fedoraproject.org/pub/fedora/linux/releases/42/Workstation/x86_64/iso/Fedora-Workstation-Live-42-1.1.x86_64.iso"
"Arch Linux|CLI|ProxMenux|https://geo.mirror.pkgbuild.com/iso/2025.07.01/archlinux-2025.07.01-x86_64.iso"
"Rocky Linux 9.5|Desktop|ProxMenux|https://download.rockylinux.org/pub/rocky/9/isos/x86_64/Rocky-9.5-x86_64-dvd.iso"
"Linux Mint 22.1|Desktop|ProxMenux|https://mirrors.edge.kernel.org/linuxmint/stable/22.1/linuxmint-22.1-cinnamon-64bit.iso"
"openSUSE Leap 15.6|Desktop|ProxMenux|https://download.opensuse.org/distribution/leap/15.6/iso/openSUSE-Leap-15.6-DVD-x86_64-Media.iso"

View File

@ -36,9 +36,6 @@ fi
load_language
initialize_cache
clear
show_proxmenux_logo
# ==========================================================
@ -78,12 +75,15 @@ function run_uupdump_creator() {
done
if [[ ${#MISSING[@]} -gt 0 ]]; then
show_proxmenux_logo
msg_info "$(translate "Installing dependencies: ${MISSING[*]}")"
apt-get update -qq >/dev/null 2>&1
if ! apt-get install -y "${MISSING[@]}" >/dev/null 2>&1; then
msg_error "$(translate "Failed to install: ${MISSING[*]}")"
sleep 2
exit 1
fi
msg_ok "$(translate "All dependencies installed and verified.")"
fi
for i in "${!CMDS[@]}"; do
@ -92,17 +92,20 @@ function run_uupdump_creator() {
fi
done
if [[ ${#FAILED[@]} -eq 0 ]]; then
msg_ok "$(translate "All dependencies installed and verified.")"
else
msg_error "$(translate "Missing commands after installation: ${FAILED[*]}")"
if [[ ${#FAILED[@]} -gt 0 ]]; then
show_proxmenux_logo
msg_error "$(translate "Missing commands after installation:") ${FAILED[*]}"
sleep 2
exit 1
fi
ISO_DIR=$(detect_iso_dir)
if [[ -z "$ISO_DIR" ]]; then
show_proxmenux_logo
msg_error "$(translate "Could not determine a valid ISO storage directory.")"
sleep 2
exit 1
fi
@ -110,40 +113,63 @@ fi
mkdir -p "$ISO_DIR"
DEFAULT_TMP="/root/uup-temp"
USER_INPUT=$(dialog --inputbox "Enter temporary folder path (default: $DEFAULT_TMP):" 10 60 "$DEFAULT_TMP" 3>&1 1>&2 2>&3)
if [[ $? -ne 0 || -z "$USER_INPUT" ]]; then
USER_INPUT="$DEFAULT_TMP"
DEFAULT_BASE="/root/uup-temp"
BASE_INPUT=$(dialog --clear --inputbox "$(translate "Enter base folder for temporary files and converter (default:") $DEFAULT_BASE):" 10 60 "$DEFAULT_BASE" 3>&1 1>&2 2>&3)
if [[ $? -ne 0 || -z "$BASE_INPUT" ]]; then
BASE_INPUT="$DEFAULT_BASE"
fi
#
if [[ "$USER_INPUT" == "$DEFAULT_TMP" ]]; then
TMP_DIR="$USER_INPUT"
CLEAN_ALL=true
else
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
RANDOM_ID=$(head /dev/urandom | tr -dc a-z0-9 | head -c 4)
TMP_DIR="${USER_INPUT%/}/uup-session-${TIMESTAMP}-${RANDOM_ID}"
CLEAN_ALL=false
fi
mkdir -p "$TMP_DIR" || {
msg_error "$(translate "Failed to create temporary directory:") $TMP_DIR"
BASE_CLEAN="$(echo "$BASE_INPUT" | sed 's:[[:space:]]*$::' | sed 's:/*$::')"
if [[ ! -d "$BASE_CLEAN" ]]; then
if ! mkdir -p "$BASE_CLEAN"; then
show_proxmenux_logo
msg_error "$(translate "The selected base folder does not exist and could not be created:") $BASE_CLEAN"
sleep 2
exit 1
fi
fi
if [[ ! -w "$BASE_CLEAN" ]]; then
show_proxmenux_logo
msg_error "$(translate "No write permissions on:") $BASE_CLEAN"
sleep 2
exit 1
}
fi
TMP_DIR="$BASE_CLEAN/uup-temp"
OUT_DIR="$ISO_DIR"
CONVERTER="$BASE_CLEAN/uup-converter"
if ! mkdir -p "$TMP_DIR"; then
show_proxmenux_logo
msg_error "$(translate "Could not create temporary directory:") $TMP_DIR"
sleep 2
exit 1
fi
if ! mkdir -p "$CONVERTER"; then
show_proxmenux_logo
msg_error "$(translate "Could not create converter directory:") $CONVERTER"
sleep 2
exit 1
fi
cd "$TMP_DIR" || { msg_error "$(translate "Failed to access:") $TMP_DIR"; exit 1; }
OUT_DIR=$(detect_iso_dir)
[[ -z "$OUT_DIR" ]] && msg_error "$(translate "Could not determine a valid ISO directory.")" && exit 1
mkdir -p "$OUT_DIR"
UUP_URL=$(whiptail --inputbox "$(translate "Paste the UUP Dump URL here")" 10 90 3>&1 1>&2 2>&3)
if [[ $? -ne 0 || -z "$UUP_URL" ]]; then
msg_warn "$(translate "Cancelled by user or empty URL.")"
return 1
fi
if [[ ! "$UUP_URL" =~ id=.+\&pack=.+\&edition=.+ ]]; then
show_proxmenux_logo
msg_error "$(translate "The URL does not contain the required parameters (id, pack, edition).")"
sleep 2
return 1
@ -155,6 +181,8 @@ LANG=$(echo "$UUP_URL" | grep -oP 'pack=\K[^&]+')
EDITION=$(echo "$UUP_URL" | grep -oP 'edition=\K[^&]+')
ARCH="amd64"
show_proxmenux_logo
echo -e
echo -e "\n${BGN}=============== UUP Dump Creator ===============${CL}"
echo -e " ${BGN}🆔 ID:${CL} ${DGN}$BUILD_ID${CL}"
echo -e " ${BGN}🌐 Language:${CL} ${DGN}$LANG${CL}"

View File

@ -1 +1 @@
1.1.2
1.1.4