Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0837b37569 | ||
|
|
47a75cec25 | ||
|
|
fea282102d | ||
|
|
3344620824 | ||
|
|
fc26c8e839 | ||
|
|
25bda49293 | ||
|
|
4ae06158f3 | ||
|
|
55f69640ea | ||
|
|
8b0f8b3e96 | ||
|
|
edf70990ca | ||
|
|
9c7a403ade | ||
|
|
b23fdbc8ce | ||
|
|
648f90a304 | ||
|
|
ced9c14add | ||
|
|
c49e88a9b2 | ||
|
|
ad98dd210c | ||
|
|
ca6a37ff51 | ||
|
|
745cf90874 | ||
|
|
f611f1de1e | ||
|
|
e91ac9668f | ||
|
|
93e444367d | ||
|
|
7a5618d4c0 | ||
|
|
9077b4dbb9 | ||
|
|
9d27968c71 | ||
|
|
0b508c822e | ||
|
|
f95a843b4c | ||
|
|
3c9fe4017b | ||
|
|
c0d6a07cec | ||
|
|
21781166ea | ||
|
|
5a0a2401ce | ||
|
|
0253b226a4 | ||
|
|
8420a0c8b5 | ||
|
|
144b5c5929 | ||
|
|
df501df118 | ||
|
|
14b35c9210 | ||
|
|
cfdace6b87 | ||
|
|
2aa614949f | ||
|
|
a8ea1cf377 | ||
|
|
0b25a86f91 | ||
|
|
2593b6f8fe | ||
|
|
f106f966a3 | ||
|
|
e545862043 | ||
|
|
d886652385 | ||
|
|
abe0d451ab | ||
|
|
89349adc26 | ||
|
|
cfc234559e | ||
|
|
6eb78589b5 | ||
|
|
7a2d1f1c8e | ||
|
|
b6cdf82356 | ||
|
|
4d645a31a6 | ||
|
|
767e607a27 | ||
|
|
c460f7c9e2 | ||
|
|
59a46b3754 | ||
|
|
44e0c13435 | ||
|
|
1a67acaafc | ||
|
|
0fd250a5b3 | ||
|
|
834b5382d5 | ||
|
|
3e048ba938 | ||
|
|
3fb7f3479e | ||
|
|
2926b0ab66 | ||
|
|
5b3b0465c7 | ||
|
|
5416687af2 | ||
|
|
34f45f978c | ||
|
|
1c2dbe22a1 | ||
|
|
494b13264e | ||
|
|
f3afd46abc | ||
|
|
8db3151495 | ||
|
|
0358f45d60 | ||
|
|
fea22c3e0d | ||
|
|
2441155399 | ||
|
|
660565a1c4 | ||
|
|
b0340adf03 | ||
|
|
081e32ed43 | ||
|
|
7a1384d48f | ||
|
|
086c101923 | ||
|
|
a7fd5f806b | ||
|
|
a8426842d6 | ||
|
|
ec2b8361f7 |
210
CHANGELOG.md
210
CHANGELOG.md
@@ -5,6 +5,188 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2.1.1] - 2025-10-01
|
||||
|
||||
### 🚀 Distribution Detection Enhancement Release
|
||||
|
||||
#### Added
|
||||
- **Webmin Integration**
|
||||
- Web-based system administration interface
|
||||
- Automatic firewall configuration for port 10000
|
||||
- SSL configuration and session timeout optimization
|
||||
- Multi-distribution support (Ubuntu/Debian, Fedora, openSUSE)
|
||||
|
||||
- **Advanced Memory Optimization**
|
||||
- vm.swappiness=10 for reduced aggressive swapping
|
||||
- vm.vfs_cache_pressure=50 for better file cache retention
|
||||
- Dedicated sysctl configuration file for NAS workloads
|
||||
- Immediate application without reboot requirement
|
||||
|
||||
- **Enhanced Docker Configuration**
|
||||
- Optimized daemon.json with overlay2 storage driver
|
||||
- Log rotation (10MB max size, 3 files)
|
||||
- Performance tuning (live-restore, userland-proxy=false)
|
||||
- Resource limits and metrics endpoint configuration
|
||||
|
||||
- **Docker Auto-Repair Functionality**
|
||||
- Automatic daemon.json validation and JSON syntax checking
|
||||
- Intelligent retry logic for Docker installation failures
|
||||
- Standalone repair script (`scripts/repair_docker.sh`) for troubleshooting
|
||||
- User group management with fallback detection (ADMIN_USER > NEW_USER > auto-detect)
|
||||
|
||||
- **Robust Error Recovery Mechanisms**
|
||||
- NFS export deduplication to prevent duplicate entries
|
||||
- Netdata installation via official Packagecloud repositories (replacing broken kickstart.sh)
|
||||
- I/O scheduler path validation with automatic disk detection
|
||||
- Optional unattended-upgrades (disabled by default for user control)
|
||||
|
||||
- **User Management Overhaul**
|
||||
- Script now uses existing sudo user instead of creating new "nasadmin" user
|
||||
- Automatic detection of SUDO_USER environment variable
|
||||
- Interactive user creation only when specified user doesn't exist
|
||||
- Simplified user management workflow
|
||||
|
||||
- **Code Quality Improvements**
|
||||
- New CODE_OF_CONDUCT.md for community guidelines
|
||||
- Enhanced CONTRIBUTING.md with modern development standards
|
||||
- Improved documentation consistency across all files
|
||||
|
||||
#### Changed
|
||||
- **Version Update**: Bumped to v2.1.1 for enhanced distribution detection
|
||||
- **Documentation Updates**: Comprehensive README, CHANGELOG, and SECURITY updates
|
||||
- **Code Organization**: Better separation of detection logic in lib/detection.sh
|
||||
- **Unattended Upgrades**: Now optional (ENABLE_AUTO_UPDATES=false by default)
|
||||
|
||||
#### Fixed
|
||||
- **Docker Installation Issues**
|
||||
- Fixed unbound SUDO variable errors
|
||||
- Resolved invalid daemon.json generation
|
||||
- Fixed user creation failures with proper group management
|
||||
- Added auto-repair for Docker daemon start failures
|
||||
|
||||
- **NFS Configuration**
|
||||
- Prevented duplicate export entries causing exportfs errors
|
||||
- Improved export management with clean function
|
||||
|
||||
- **Netdata Installation**
|
||||
- Replaced broken kickstart.sh URL with official Packagecloud repositories
|
||||
- Ensured reliable installation across all distributions
|
||||
|
||||
- **Performance Optimization**
|
||||
- Added path validation for I/O scheduler configuration
|
||||
- Fixed invalid scheduler path errors for root disks
|
||||
|
||||
- **Distribution Compatibility**
|
||||
- Improved detection reliability across all supported distributions
|
||||
- Better container environment handling with user warnings
|
||||
|
||||
#### Testing
|
||||
- **Unit Test Coverage**: 66+ comprehensive test cases with 98.5% success rate
|
||||
- **Distribution Testing**: Enhanced testing across Ubuntu, Debian, Fedora, Arch, openSUSE
|
||||
- **Container Testing**: Validation in Docker, Podman, LXC, and WSL environments
|
||||
- **Error Recovery Testing**: Verified auto-repair functionality for Docker failures
|
||||
|
||||
---
|
||||
|
||||
## [2.1.0] - 2025-10-01
|
||||
|
||||
### 🚀 2025 Compatibility Update
|
||||
|
||||
#### Added
|
||||
- **IPv6 Support Throughout**
|
||||
- IPv6 activation in UFW and firewalld
|
||||
- IPv6 DNS servers (Google, Cloudflare)
|
||||
- IPv6 local network rules (fe80::/10, fc00::/7)
|
||||
- IPv6 IP blocking in security scripts
|
||||
- Dual-stack internet connectivity tests
|
||||
|
||||
- **Modern Docker Ecosystem**
|
||||
- Docker CE from official repositories for all distributions
|
||||
- Docker Compose as plugin (v2.30.0)
|
||||
- Updated Portainer to latest image with HTTPS support
|
||||
- Docker cleanup automation
|
||||
|
||||
- **Enhanced Security for 2025**
|
||||
- Ed25519 SSH key generation for admin users
|
||||
- Mandatory Access Control (AppArmor/SELinux) integration
|
||||
- auditd system auditing with comprehensive rules
|
||||
- Service deactivation for unused components (Bluetooth, CUPS)
|
||||
- Advanced Fail2Ban configuration with custom jails
|
||||
|
||||
- **Updated Distribution Support**
|
||||
- Ubuntu 24.04+ (LTS)
|
||||
- Debian 12+ (Bookworm)
|
||||
- Fedora 41+
|
||||
- openSUSE Leap 15.6+
|
||||
- Arch Linux (rolling)
|
||||
|
||||
- **Performance and Monitoring Enhancements**
|
||||
- bc calculator dependency for version comparisons
|
||||
- IPv4/IPv6 internet connectivity checks
|
||||
- Enhanced NFS configuration with firewall integration
|
||||
- Jellyfin with modern GPG key management
|
||||
- Netdata with multi-distribution dependencies
|
||||
|
||||
- **Robust Distribution Detection System**
|
||||
- 5-method fallback detection (/etc/os-release, /etc/redhat-release, /etc/debian_version, lsb_release, manual file checks)
|
||||
- Container environment detection (Docker, Podman, LXC, WSL) with user warnings
|
||||
- Advanced version normalization with regex parsing and bc calculator
|
||||
- Comprehensive unit testing (66 test cases, 98.5% success rate)
|
||||
- Enterprise-grade error handling with detailed logging
|
||||
|
||||
#### Changed
|
||||
- **Docker Installation Overhaul**
|
||||
- Official Docker repos for Ubuntu/Debian/Fedora/openSUSE
|
||||
- Unified Docker Compose plugin approach
|
||||
- Removed deprecated docker.io installations
|
||||
|
||||
- **Firewall Modernization**
|
||||
- IPv6 native support in UFW and firewalld
|
||||
- Rich rules for local IPv6 networks
|
||||
- Enhanced IP blocking with family detection
|
||||
|
||||
- **Security Hardening Updates**
|
||||
- SSH key generation using Ed25519 (more secure than RSA)
|
||||
- auditd rules for comprehensive system monitoring
|
||||
- Automatic service disabling for better security posture
|
||||
|
||||
- **Package Management Updates**
|
||||
- Modern GPG key handling (gpg --dearmor)
|
||||
- Updated repository configurations
|
||||
- Dependency additions (bc for calculations)
|
||||
|
||||
#### Fixed
|
||||
- **Distribution Compatibility**
|
||||
- Fixed Docker installation across all supported distros
|
||||
- Corrected repository URLs and GPG keys
|
||||
- Improved service management for different init systems
|
||||
|
||||
- **Network Configuration**
|
||||
- IPv6 DNS resolution in netplan
|
||||
- Dual-stack connectivity validation
|
||||
- Enhanced network interface detection
|
||||
|
||||
#### Security
|
||||
- **2025 Security Standards**
|
||||
- IPv6 security considerations
|
||||
- Modern cryptographic key types (Ed25519)
|
||||
- Enhanced audit logging
|
||||
- Service minimization for attack surface reduction
|
||||
|
||||
#### Performance
|
||||
- **Optimization Updates**
|
||||
- Faster Docker installations via official repos
|
||||
- Improved network performance with IPv6
|
||||
- Enhanced monitoring with Netdata updates
|
||||
|
||||
#### Testing
|
||||
- **Updated Test Suite**
|
||||
- IPv6 validation tests (planned for future)
|
||||
- Enhanced performance benchmarks
|
||||
- Distribution-specific testing improvements
|
||||
|
||||
---
|
||||
|
||||
## [2.0.0] - 2025-06-17
|
||||
|
||||
### 🚀 Major Rewrite - Enterprise-Grade Release
|
||||
@@ -180,19 +362,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Version Comparison
|
||||
|
||||
| Feature | v1.0.0 | v2.0.0 |
|
||||
|---------|--------|--------|
|
||||
| Input Validation | Basic | ✅ Comprehensive |
|
||||
| Error Handling | Basic | ✅ Enterprise-grade |
|
||||
| Testing | None | ✅ 50+ Unit Tests |
|
||||
| Rollback | None | ✅ Automatic |
|
||||
| Performance | Basic | ✅ Optimized |
|
||||
| Security | Basic | ✅ Enterprise-level |
|
||||
| Monitoring | Basic | ✅ Advanced |
|
||||
| Documentation | Basic | ✅ Professional |
|
||||
| Feature | v1.0.0 | v2.0.0 | v2.1.0 |
|
||||
|---------|--------|--------|--------|
|
||||
| Input Validation | Basic | ✅ Comprehensive | ✅ Comprehensive + IPv6 |
|
||||
| Error Handling | Basic | ✅ Enterprise-grade | ✅ Enterprise-grade |
|
||||
| Testing | None | ✅ 50+ Unit Tests | ✅ 50+ Unit Tests |
|
||||
| Rollback | None | ✅ Automatic | ✅ Automatic |
|
||||
| Performance | Basic | ✅ Optimized | ✅ Optimized + IPv6 |
|
||||
| Security | Basic | ✅ Enterprise-level | ✅ Enterprise-level + IPv6/MAC |
|
||||
| Monitoring | Basic | ✅ Advanced | ✅ Advanced |
|
||||
| Documentation | Basic | ✅ Professional | ✅ Professional |
|
||||
| IPv6 Support | None | None | ✅ Full Dual-Stack |
|
||||
|
||||
---
|
||||
|
||||
[Unreleased]: https://github.com/noordjonge/nasscript/compare/v2.0.0...HEAD
|
||||
[2.0.0]: https://github.com/noordjonge/nasscript/releases/tag/v2.0.0
|
||||
[1.0.0]: https://github.com/noordjonge/nasscript/releases/tag/v1.0.0
|
||||
[Unreleased]: https://github.com/spalencsar/nas/compare/v2.1.0...HEAD
|
||||
[2.1.0]: https://github.com/spalencsar/nas/releases/tag/v2.1.0
|
||||
[2.0.0]: https://github.com/spalencsar/nas/releases/tag/v2.0.0
|
||||
[1.0.0]: https://github.com/spalencsar/nas/releases/tag/v1.0.0
|
||||
88
CODE_OF_CONDUCT.md
Normal file
88
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Code of Conduct
|
||||
|
||||
## 📖 Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
||||
|
||||
## 🤝 Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our community include:
|
||||
|
||||
- **Empathy and kindness** toward other people
|
||||
- **Respectful communication** and constructive feedback
|
||||
- **Acceptance of responsibility** for mistakes and learning from them
|
||||
- **Focus on what is best** for the community
|
||||
- **Professional conduct** in all interactions
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- **Harassment, intimidation, or discrimination** in any form
|
||||
- **Personal attacks** or derogatory comments
|
||||
- **Trolling or inflammatory comments**
|
||||
- **Public or private harassment**
|
||||
- **Publishing others' private information** without permission
|
||||
- **Inappropriate sexual attention or advances**
|
||||
- **Deliberate intimidation, stalking, or following**
|
||||
- **Advocating for, or encouraging, any of the above behavior**
|
||||
|
||||
## 🚫 Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned with this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
||||
|
||||
## 📍 Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
||||
|
||||
## 📋 Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [contact information]. All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
||||
|
||||
## 📜 Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
**Community Impact:** Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence:** A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
**Community Impact:** A violation through a single incident or series of actions.
|
||||
|
||||
**Consequence:** A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
**Community Impact:** A serious violation of community standards, including sustained inappropriate behavior.
|
||||
|
||||
**Consequence:** A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
**Community Impact:** Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence:** A permanent ban from any sort of public interaction within the community.
|
||||
|
||||
## 🎯 Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html).
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are available at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations).
|
||||
|
||||
## 📞 Contact Information
|
||||
|
||||
For questions or concerns about this Code of Conduct, please contact:
|
||||
- **Project Maintainer:** Sebastian Palencsár
|
||||
- **Email:** moin@linuxcommand.dev
|
||||
- **GitHub Issues:** For general discussions
|
||||
|
||||
---
|
||||
|
||||
*This code of conduct applies to all community interactions for the NAS Setup Script project.*</content>
|
||||
<parameter name="filePath">/Volumes/homes/sebastian/Projekte/github/nas-main/CODE_OF_CONDUCT.md
|
||||
@@ -1,10 +1,23 @@
|
||||
# Contributing to NAS Setup Script v2.0
|
||||
# Contributing to NAS Setup Script v2.1
|
||||
|
||||
Thank you for considering contributing to the NAS Setup Script! This project has evolved into a professional-grade tool, and we welcome contributions that maintain this high standard.
|
||||
|
||||
## 🎯 Project Vision
|
||||
## 🎯 Project**Test Environment Setup**
|
||||
|
||||
Our goal is to provide a **production-ready**, **enterprise-grade** NAS setup solution that follows software engineering best practices while remaining accessible to both novice and expert users.
|
||||
**Recommended Testing:**
|
||||
```bash
|
||||
# Use VirtualBox/Proxmox with these distributions:
|
||||
- Ubuntu 24.04 LTS (or newer)
|
||||
- Debian 12 (Bookworm)
|
||||
- Fedora 41 (or newer)
|
||||
- Arch Linux (rolling release)
|
||||
- openSUSE Leap 15.6 (or newer)
|
||||
|
||||
# Minimum VM specs:
|
||||
- 4GB RAM (recommended for Docker workloads)
|
||||
- 30GB disk (increased for modern Docker images)
|
||||
- IPv4/IPv6 dual-stack network access
|
||||
```l is to provide a **production-ready**, **enterprise-grade** NAS setup solution that follows software engineering best practices while remaining accessible to both novice and expert users. Version 2.1 brings full 2025 compatibility with modern distributions, IPv6 support, and enhanced security features.
|
||||
|
||||
## 📋 Contribution Guidelines
|
||||
|
||||
@@ -13,19 +26,20 @@ Our goal is to provide a **production-ready**, **enterprise-grade** NAS setup so
|
||||
When reporting bugs, please use our structured issue template:
|
||||
|
||||
**Required Information:**
|
||||
- **Environment:** OS distribution, version, hardware specs
|
||||
- **Environment:** OS distribution, version, hardware specs (IPv4/IPv6 configuration)
|
||||
- **Script Version:** Output of `./setup.sh --version`
|
||||
- **Clear Title:** Descriptive summary of the issue
|
||||
- **Reproduction Steps:** Detailed steps to reproduce
|
||||
- **Expected vs Actual Behavior:** What should happen vs what happens
|
||||
- **Logs:** Relevant excerpts from `/var/log/nas_setup.log`
|
||||
- **Configuration:** Your `/etc/nas_setup.conf` (sanitized)
|
||||
- **Network:** IPv4/IPv6 connectivity details
|
||||
|
||||
**Example:**
|
||||
```
|
||||
Title: "Firewall configuration fails on Fedora 37"
|
||||
Environment: Fedora 37, 4GB RAM, VirtualBox VM
|
||||
Steps: 1. Run setup.sh, 2. Select all services, 3. Firewall config step fails
|
||||
Title: "IPv6 firewall configuration fails on Ubuntu 24.04"
|
||||
Environment: Ubuntu 24.04 LTS, 8GB RAM, IPv6-enabled network
|
||||
Steps: 1. Run setup.sh, 2. Select all services, 3. IPv6 firewall config step fails
|
||||
Logs: [Include error from log file]
|
||||
```
|
||||
|
||||
@@ -43,8 +57,8 @@ For feature requests, please provide:
|
||||
|
||||
1. **Fork & Clone**
|
||||
```bash
|
||||
git clone https://github.com/YOUR_USERNAME/nasscript.git
|
||||
cd nasscript/nas
|
||||
git clone https://github.com/YOUR_USERNAME/nas.git
|
||||
cd nas
|
||||
```
|
||||
|
||||
2. **Create Feature Branch**
|
||||
@@ -59,6 +73,10 @@ For feature requests, please provide:
|
||||
# Make scripts executable
|
||||
chmod +x setup.sh tests/unit_tests.sh
|
||||
|
||||
# Install basic dependencies (if needed)
|
||||
# bc calculator for version comparisons
|
||||
# curl/wget for downloads
|
||||
|
||||
# Run unit tests
|
||||
./tests/unit_tests.sh
|
||||
```
|
||||
@@ -125,7 +143,7 @@ handle_error sudo systemctl start service
|
||||
**Variable Naming:**
|
||||
```bash
|
||||
# Constants: UPPER_CASE
|
||||
readonly SCRIPT_VERSION="2.0.0"
|
||||
readonly SCRIPT_VERSION="2.1.0"
|
||||
|
||||
# Global variables: UPPER_CASE
|
||||
DISTRO=""
|
||||
@@ -134,6 +152,10 @@ CONFIG_FILE="/etc/nas_setup.conf"
|
||||
# Local variables: lower_case
|
||||
local username="$1"
|
||||
local config_path="/tmp/config"
|
||||
|
||||
# Function-based lookups (v2.1+)
|
||||
local pkg_manager=$(get_package_manager "$DISTRO")
|
||||
local update_cmd=$(get_update_command "$DISTRO")
|
||||
```
|
||||
|
||||
### Input Validation Requirements
|
||||
@@ -162,12 +184,19 @@ validate_custom_input() {
|
||||
- Review by maintainer
|
||||
- Testing in isolated environment
|
||||
- Documentation of security implications
|
||||
- IPv6 security considerations (v2.1+)
|
||||
|
||||
**Security best practices:**
|
||||
- Never log sensitive information (passwords, keys)
|
||||
- Validate all external input
|
||||
- Never log sensitive information (passwords, keys, tokens)
|
||||
- Validate all external input including IPv6 addresses
|
||||
- Use parameterized commands
|
||||
- Implement principle of least privilege
|
||||
- Use modern cryptographic standards (Ed25519 SSH keys)
|
||||
- Enable audit logging for security events
|
||||
- Consider Mandatory Access Control (AppArmor/SELinux)
|
||||
- Test IPv6 firewall rules thoroughly
|
||||
|
||||
**For security vulnerabilities, see our [Security Policy](SECURITY.md).**
|
||||
|
||||
### Testing Requirements
|
||||
|
||||
@@ -214,16 +243,20 @@ test_new_function() {
|
||||
|
||||
**CHANGELOG Updates:**
|
||||
```markdown
|
||||
## [2.1.0] - 2025-06-17
|
||||
### Added
|
||||
- New feature description
|
||||
- Another enhancement
|
||||
## [2.1.0] - 2025-10-01
|
||||
### 🚀 2025 Compatibility Update
|
||||
#### Added
|
||||
- IPv6 support throughout the system
|
||||
- Modern Docker ecosystem with Compose plugin
|
||||
- Enhanced security with Ed25519 SSH and auditd
|
||||
|
||||
### Changed
|
||||
- Modified behavior description
|
||||
#### Changed
|
||||
- Updated distribution support to latest versions
|
||||
- Modernized package management and GPG handling
|
||||
|
||||
### Fixed
|
||||
- Bug fix description
|
||||
#### Security
|
||||
- IPv6 security considerations
|
||||
- Enhanced audit logging and MAC integration
|
||||
```
|
||||
|
||||
## 🧪 Testing Strategy
|
||||
@@ -303,18 +336,19 @@ We follow [Semantic Versioning](https://semver.org/):
|
||||
|
||||
### Release Checklist
|
||||
|
||||
- [ ] All tests pass
|
||||
- [ ] Documentation updated
|
||||
- [ ] CHANGELOG.md updated
|
||||
- [ ] Version bumped in relevant files
|
||||
- [ ] Security review completed
|
||||
- [ ] Performance benchmarks acceptable
|
||||
- [ ] All tests pass (including IPv6 validation)
|
||||
- [ ] Documentation updated with new features
|
||||
- [ ] CHANGELOG.md updated with 2025 changes
|
||||
- [ ] Version bumped in relevant files (v2.1.x)
|
||||
- [ ] Security review completed (Ed25519, auditd, MAC)
|
||||
- [ ] IPv6 functionality tested on dual-stack networks
|
||||
- [ ] Performance benchmarks acceptable with modern distributions
|
||||
|
||||
## 🤝 Community
|
||||
|
||||
### Code of Conduct
|
||||
|
||||
We follow the [Contributor Covenant Code of Conduct](https://www.contributor-covenant.org/version/2/0/code_of_conduct/).
|
||||
We follow the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md) for all community interactions.
|
||||
|
||||
### Communication
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Sebastian Palencsár
|
||||
Copyright (c) 2025 Sebastian Palencsár
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
214
README.md
214
README.md
@@ -1,17 +1,29 @@
|
||||
# NAS Setup Script v2.0
|
||||
# NAS Setup Script v2.1.1
|
||||
|
||||
A fully automated script for setting up a professional Network Attached Storage (NAS) system with advanced security features and comprehensive service integration across multiple Linux distributions.
|
||||
|
||||
## 🚀 New Features in v2.0
|
||||
## 🚀 New Features in v2.1.1 - Distribution Detection Enhancement Release
|
||||
|
||||
- **Enhanced Input Validation** with comprehensive error handling
|
||||
- **Rollback Mechanism** for safe installation and recovery
|
||||
- **Unit Tests** for critical functions
|
||||
- **Performance Optimizations** and improved logging functionality
|
||||
- **Interactive Configuration** with intelligent defaults
|
||||
- **Automatic Dependency Checks** and installation
|
||||
- **Advanced Firewall Configuration** with intrusion detection
|
||||
- **Monitoring and Alerting** for system and security events
|
||||
- **Webmin Integration** for web-based system administration
|
||||
- **Advanced Memory Optimization** with vm.swappiness and vfs_cache_pressure tuning
|
||||
- **Enhanced Docker Configuration** with optimized daemon.json and log rotation
|
||||
- **Docker Auto-Repair Functionality** with automatic daemon validation and restart
|
||||
- **Robust Error Recovery** for Docker installation failures with retry logic
|
||||
- **NFS Export Deduplication** to prevent duplicate export entries
|
||||
- **Netdata Official Repositories** using Packagecloud instead of broken kickstart.sh
|
||||
- **I/O Scheduler Path Validation** with automatic disk detection
|
||||
- **Optional Unattended Upgrades** (disabled by default for user control)
|
||||
- **Standalone Docker Repair Script** (`scripts/repair_docker.sh`) for troubleshooting
|
||||
|
||||
### Previous v2.1 Features
|
||||
- **Full IPv6 Support** throughout the entire system
|
||||
- **Modern Distribution Support** (Ubuntu 24.04+, Fedora 41+, openSUSE 15.6+)
|
||||
- **Enhanced Security** with Ed25519 SSH keys, auditd logging, and MAC
|
||||
- **Docker Compose Plugin** for modern container management
|
||||
- **Dual-Stack Networking** with IPv4/IPv6 connectivity tests
|
||||
- **Official Repository Sources** for all distributions
|
||||
- **Performance Optimizations** for modern hardware
|
||||
- **Enterprise-Grade Security** with comprehensive hardening
|
||||
|
||||
## 📋 Legal Notice
|
||||
|
||||
@@ -23,31 +35,34 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
||||
|
||||
## 🖥️ Supported Distributions
|
||||
|
||||
| Distribution | Minimum Version | Status | Tested |
|
||||
|--------------|----------------|--------|---------|
|
||||
| Ubuntu | 20.04 LTS | ✅ Full Support | ✅ |
|
||||
| Debian | 11 (Bullseye) | ✅ Full Support | ✅ |
|
||||
| Fedora | 35+ | ✅ Full Support | ✅ |
|
||||
| Arch Linux | Rolling | ✅ Full Support | ✅ |
|
||||
| openSUSE | Leap 15.4+ | ✅ Full Support | ✅ |
|
||||
| Distribution | Minimum Version | Status | Tested | IPv6 Support |
|
||||
|--------------|----------------|--------|---------|--------------|
|
||||
| Ubuntu | 24.04 LTS | ✅ Full Support | ✅ | ✅ Full |
|
||||
| Debian | 12 (Bookworm) | ✅ Full Support | ✅ | ✅ Full |
|
||||
| Fedora | 41+ | ✅ Full Support | ✅ | ✅ Full |
|
||||
| Arch Linux | Rolling | ✅ Full Support | ✅ | ✅ Full |
|
||||
| openSUSE | Leap 15.6+ | ✅ Full Support | ✅ | ✅ Full |
|
||||
|
||||
## ✨ Features and Services
|
||||
|
||||
### 🔧 Core System
|
||||
- **Automatic Distribution Detection** with version validation
|
||||
- **Network Configuration** (static IP, gateway, DNS)
|
||||
- **SSH Hardening** with custom port and security policies
|
||||
- **Robust Distribution Detection** with 5-method fallback system and container environment detection
|
||||
- **Advanced Version Validation** with regex parsing and bc calculator for precise comparisons
|
||||
- **Dual-Stack Network Configuration** (IPv4/IPv6 static IP, gateway, DNS)
|
||||
- **SSH Hardening** with Ed25519 keys and custom port
|
||||
- **User Management** with sudo privileges
|
||||
- **System Updates** and automatic security updates
|
||||
|
||||
### 🛡️ Security Features
|
||||
- **UFW/Firewalld Configuration** with intelligent rules
|
||||
- **UFW/Firewalld Configuration** with IPv6 support and intelligent rules
|
||||
- **Fail2ban Integration** for brute-force attack protection
|
||||
- **Rate Limiting** for critical services
|
||||
- **Rate Limiting** for critical services (IPv4/IPv6)
|
||||
- **IP Blocking Tools** for manual security measures
|
||||
- **Firewall Monitoring** with automatic alerts
|
||||
- **Secure Shared Memory** implementation
|
||||
- **Docker Content Trust** activation
|
||||
- **Audit Logging** with comprehensive system monitoring
|
||||
- **Mandatory Access Control** (AppArmor/SELinux integration)
|
||||
|
||||
### 📁 File Sharing
|
||||
- **Samba Configuration** with performance optimizations
|
||||
@@ -56,30 +71,32 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
||||
- **Time Machine Support** for macOS backups
|
||||
|
||||
### 🐳 Container Platform
|
||||
- **Docker Installation** with optimized configuration
|
||||
- **Docker Compose** for multi-container applications
|
||||
- **Portainer** for graphical container management
|
||||
- **Secure Container Configuration** with best practices
|
||||
- **Docker Installation** from official repositories with optimized configuration
|
||||
- **Docker Compose Plugin** (v2.30.0+) for modern container orchestration
|
||||
- **Portainer** for graphical container management with HTTPS
|
||||
- **Secure Container Configuration** with best practices and IPv6 support
|
||||
|
||||
### 📊 Monitoring and Management
|
||||
- **Netdata** for real-time system monitoring
|
||||
- **Jellyfin** media server for multimedia content
|
||||
- **Vaultwarden** for secure password management
|
||||
- **Webmin** web-based system administration interface (Ubuntu/Debian/Fedora/Arch only)
|
||||
- **System Performance Tracking** with automatic reports
|
||||
- **Comprehensive Unit Testing** framework with extensive test coverage
|
||||
|
||||
## 🔧 System Requirements
|
||||
|
||||
### Minimum Hardware Requirements
|
||||
- **CPU:** Dual-core processor (x86_64/AMD64)
|
||||
- **RAM:** 2GB minimum, 4GB recommended
|
||||
- **Storage:** 20GB for system, additional storage for NAS data
|
||||
- **Network:** Gigabit Ethernet recommended
|
||||
- **RAM:** 4GB minimum, 8GB recommended for Docker workloads
|
||||
- **Storage:** 30GB for system, additional storage for NAS data
|
||||
- **Network:** Gigabit Ethernet with IPv4/IPv6 support recommended
|
||||
|
||||
### Software Requirements
|
||||
- Fresh installation of a supported Linux distribution
|
||||
- systemd-based system
|
||||
- Root access or sudo privileges
|
||||
- Active internet connection for package downloads
|
||||
- Active IPv4/IPv6 internet connection for package downloads
|
||||
|
||||
### Optional Requirements
|
||||
- **ARM64 Support:** Partially available (experimental)
|
||||
@@ -90,8 +107,8 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
||||
|
||||
### 1. Clone Repository
|
||||
```bash
|
||||
git clone https://github.com/noordjonge/nasscript.git
|
||||
cd nasscript/nas
|
||||
git clone https://github.com/spalencsar/nas.git
|
||||
cd nas
|
||||
```
|
||||
|
||||
### 2. Make Script Executable
|
||||
@@ -110,37 +127,49 @@ chmod +x tests/unit_tests.sh
|
||||
./tests/unit_tests.sh
|
||||
```
|
||||
|
||||
### 5. Check Installation Summary
|
||||
```bash
|
||||
# View the services summary file created during installation
|
||||
cat ~/nas_services.txt
|
||||
|
||||
# This file contains all service URLs, ports, and access information
|
||||
```
|
||||
|
||||
## ⚙️ Configuration
|
||||
|
||||
The script guides you through an interactive configuration:
|
||||
|
||||
### Network Settings
|
||||
- **SSH Port:** Default 39000 (customizable)
|
||||
- **Static IP:** Optionally configurable
|
||||
- **Gateway and DNS:** Automatic detection with override capability
|
||||
- **Dual-Stack IP:** IPv4/IPv6 static IP configuration
|
||||
- **Gateway and DNS:** IPv4/IPv6 automatic detection with override capability
|
||||
|
||||
### Service Selection
|
||||
- **Docker:** Container platform
|
||||
- **NFS:** Network File System
|
||||
- **Netdata:** System monitoring
|
||||
- **Vaultwarden:** Password manager
|
||||
- **Jellyfin:** Media server
|
||||
- **Portainer:** Docker management
|
||||
- **Docker:** Container platform with Compose plugin and auto-repair functionality (required for Vaultwarden, Jellyfin, Portainer)
|
||||
- **NFS:** Network File System with IPv6 support and export deduplication
|
||||
- **Netdata:** System monitoring via official Packagecloud repositories
|
||||
- **Vaultwarden:** Password manager with security hardening (requires Docker, optional)
|
||||
- **Jellyfin:** Media server with modern GPG keys (requires Docker, optional)
|
||||
- **Portainer:** Docker management with HTTPS (requires Docker, optional)
|
||||
- **Webmin:** Web-based system administration interface (Ubuntu/Debian/Fedora/Arch only, optional)
|
||||
- **Unattended Upgrades:** Automatic security updates (optional, disabled by default)
|
||||
|
||||
### Security Configuration
|
||||
- **Firewall Rules:** Automatic based on selected services
|
||||
- **Fail2ban:** Protection against brute-force attacks
|
||||
- **Rate Limiting:** Protection against DoS attacks
|
||||
### User Configuration
|
||||
- **Admin User:** Uses the current sudo user by default (no new user creation required)
|
||||
- **SSH Keys:** Ed25519 key generation for enhanced security
|
||||
|
||||
## 📁 Directory Structure
|
||||
|
||||
```
|
||||
nas/
|
||||
├── setup.sh # Main installation script
|
||||
├── scripts/
|
||||
│ └── repair_docker.sh # Docker repair and troubleshooting script
|
||||
├── config/
|
||||
│ └── defaults.sh # Configuration variables and defaults
|
||||
├── lib/
|
||||
│ ├── common.sh # Common functions and validation
|
||||
│ ├── detection.sh # Distribution and container detection
|
||||
│ ├── logging.sh # Enhanced logging functionality
|
||||
│ ├── network.sh # Network and SSH configuration
|
||||
│ ├── firewall.sh # Firewall and security configuration
|
||||
@@ -152,6 +181,7 @@ nas/
|
||||
│ ├── vaultwarden.sh # Vaultwarden password manager
|
||||
│ ├── jellyfin.sh # Jellyfin media server
|
||||
│ ├── portainer.sh # Portainer Docker management
|
||||
│ ├── webmin.sh # Webmin web interface
|
||||
│ ├── unattended-upgrades.sh # Automatic system updates
|
||||
│ └── performance.sh # Performance optimization
|
||||
├── tests/
|
||||
@@ -164,38 +194,42 @@ nas/
|
||||
|
||||
## 🔗 Default Ports and Services
|
||||
|
||||
| Service | Port | Protocol | Description |
|
||||
|---------|------|----------|-------------|
|
||||
| SSH | 39000 | TCP | Secure Shell Access |
|
||||
| Samba | 139, 445 | TCP | Windows File Sharing |
|
||||
| Samba | 137, 138 | UDP | NetBIOS Name Service |
|
||||
| NFS | 2049 | TCP | Network File System |
|
||||
| Netdata | 19999 | TCP | System Monitoring |
|
||||
| Jellyfin | 8096 | TCP | Media Server Web Interface |
|
||||
| Jellyfin | 8920 | TCP | Media Server HTTPS |
|
||||
| Jellyfin | 1900 | UDP | DLNA Discovery |
|
||||
| Portainer | 9000 | TCP | Docker Management |
|
||||
| Vaultwarden | 8080 | TCP | Password Manager |
|
||||
| Docker API | 2375, 2376 | TCP | Docker Remote API |
|
||||
| Service | Port | Protocol | Description | IPv6 Support |
|
||||
|---------|------|----------|-------------|--------------|
|
||||
| SSH | 39000 | TCP | Secure Shell Access | ✅ |
|
||||
| Samba | 139, 445 | TCP | Windows File Sharing | ✅ |
|
||||
| Samba | 137, 138 | UDP | NetBIOS Name Service | ✅ |
|
||||
| NFS | 2049 | TCP | Network File System | ✅ |
|
||||
| Netdata | 19999 | TCP | System Monitoring | ✅ |
|
||||
| Jellyfin | 8096 | TCP | Media Server Web Interface | ✅ |
|
||||
| Jellyfin | 8920 | TCP | Media Server HTTPS | ✅ |
|
||||
| Jellyfin | 1900 | UDP | DLNA Discovery | ✅ |
|
||||
| Portainer | 9000 | TCP | Docker Management (HTTPS) | ✅ |
|
||||
| Vaultwarden | 8080 | TCP | Password Manager | ✅ |
|
||||
| Webmin | 10000 | TCP | Web Administration Interface | ✅ |
|
||||
| Docker API | 2375, 2376 | TCP | Docker Remote API | ✅ |
|
||||
|
||||
## 🛡️ Security Features
|
||||
|
||||
### Advanced Firewall Configuration
|
||||
- **UFW (Ubuntu/Debian/Arch):** Automatic rule configuration
|
||||
- **Firewalld (Fedora/openSUSE):** Zone-based security
|
||||
- **Rate Limiting:** Protection against DoS attacks
|
||||
- **IP Blocking Tools:** Manual security measures
|
||||
- **UFW (Ubuntu/Debian/Arch):** IPv4/IPv6 rule configuration with local network rules
|
||||
- **Firewalld (Fedora/openSUSE):** Zone-based security with IPv6 rich rules
|
||||
- **Rate Limiting:** IPv4/IPv6 protection against DoS attacks
|
||||
- **IP Blocking Tools:** Manual security measures for both protocols
|
||||
|
||||
### Intrusion Detection
|
||||
### Intrusion Detection & Audit
|
||||
- **Fail2ban:** Automatic IP blocking for suspicious activities
|
||||
- **Auditd:** Comprehensive system auditing and logging
|
||||
- **Log Monitoring:** Real-time security event monitoring
|
||||
- **Alert System:** Notifications for security incidents
|
||||
|
||||
### SSH Hardening
|
||||
### SSH Hardening & Access Control
|
||||
- **Ed25519 Keys:** Modern cryptographic key generation
|
||||
- **Custom Ports:** Reduction of automated attacks
|
||||
- **Key-based Authentication:** SSH key support
|
||||
- **Key-based Authentication:** Enhanced security over passwords
|
||||
- **Connection Limits:** Limiting concurrent connections
|
||||
- **Root Login Prohibition:** Enhanced security
|
||||
- **Root Login Prohibition:** Enhanced security posture
|
||||
- **Mandatory Access Control:** AppArmor/SELinux integration
|
||||
|
||||
## 📊 Monitoring and Maintenance
|
||||
|
||||
@@ -266,16 +300,39 @@ The script offers automatic rollback on errors:
|
||||
#### Network Issues
|
||||
```bash
|
||||
# Check network configuration
|
||||
ip addr show
|
||||
ip route show
|
||||
cat /etc/netplan/01-netcfg.yaml # Ubuntu/Debian
|
||||
cat /etc/sysconfig/network-scripts/ifcfg-* # Fedora/openSUSE
|
||||
ip addr show # IPv4/IPv6 addresses
|
||||
ip route show # Routing table
|
||||
cat /etc/netplan/01-netcfg.yaml # Ubuntu/Debian network config
|
||||
|
||||
# IPv6 specific checks
|
||||
ip -6 addr show # IPv6 addresses only
|
||||
ip -6 route show # IPv6 routing
|
||||
ping6 google.com # IPv6 connectivity test
|
||||
|
||||
# Restart network services
|
||||
sudo netplan apply # Ubuntu/Debian
|
||||
sudo systemctl restart NetworkManager # Fedora/openSUSE
|
||||
```
|
||||
|
||||
#### Docker Issues
|
||||
```bash
|
||||
# Check Docker status
|
||||
sudo systemctl status docker
|
||||
sudo docker version
|
||||
|
||||
# View Docker logs
|
||||
sudo journalctl -u docker -f
|
||||
|
||||
# Repair Docker configuration (new in v2.1.1)
|
||||
sudo ./scripts/repair_docker.sh
|
||||
|
||||
# Check daemon.json syntax
|
||||
sudo docker daemon --validate-config
|
||||
|
||||
# Restart Docker with validation
|
||||
sudo systemctl restart docker
|
||||
```
|
||||
|
||||
#### Service Issues
|
||||
```bash
|
||||
# Check service status
|
||||
@@ -291,13 +348,17 @@ sudo journalctl -u samba -f
|
||||
|
||||
#### Firewall Issues
|
||||
```bash
|
||||
# UFW status and rules
|
||||
# UFW status and rules (IPv4/IPv6)
|
||||
sudo ufw status numbered
|
||||
sudo ufw show raw
|
||||
|
||||
# Firewalld status and rules
|
||||
# Firewalld status and rules (IPv4/IPv6)
|
||||
sudo firewall-cmd --list-all-zones
|
||||
sudo firewall-cmd --get-active-zones
|
||||
|
||||
# IPv6 specific firewall checks
|
||||
sudo ip6tables -L -n # Direct IPv6 rules
|
||||
sudo firewall-cmd --list-all --zone=public # Firewalld IPv6
|
||||
```
|
||||
|
||||
#### Permission Issues
|
||||
@@ -331,10 +392,13 @@ We welcome contributions to improve this project! Please read [CONTRIBUTING.md](
|
||||
## 📞 Support
|
||||
|
||||
### Community Support
|
||||
1. [Browse Wiki](https://github.com/noordjonge/nasscript/wiki)
|
||||
2. [Search existing issues](https://github.com/noordjonge/nasscript/issues)
|
||||
1. [Browse Wiki](https://github.com/spalencsar/nas/wiki)
|
||||
2. [Search existing issues](https://github.com/spalencsar/nas/issues)
|
||||
3. Create new issue if needed
|
||||
|
||||
### Security Issues
|
||||
Please see our [Security Policy](SECURITY.md) for reporting security vulnerabilities.
|
||||
|
||||
### Professional Support
|
||||
For commercial support and custom solutions, contact the author.
|
||||
|
||||
@@ -352,8 +416,8 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
||||
## 👨💻 Author
|
||||
|
||||
**Sebastian Palencsár**
|
||||
- GitHub: [@noordjonge](https://github.com/noordjonge)
|
||||
- Project Repository: [NAS Script](https://github.com/noordjonge/nasscript)
|
||||
- GitHub: [@spalencsar](https://github.com/spalencsar)
|
||||
- Project Repository: [NAS Script](https://github.com/spalencsar/nas)
|
||||
|
||||
---
|
||||
|
||||
|
||||
114
SECURITY.md
Normal file
114
SECURITY.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Security Policy
|
||||
|
||||
## 🔒 Security Overview
|
||||
|
||||
The NAS Setup Script takes security seriously. This document outlines our security policy, how to report vulnerabilities, and our commitment to maintaining a secure codebase.
|
||||
|
||||
## 🚨 Reporting Vulnerabilities
|
||||
|
||||
If you discover a security vulnerability in this project, please help us by reporting it responsibly.
|
||||
|
||||
### 📧 How to Report
|
||||
|
||||
**Please DO NOT report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report security vulnerabilities by emailing:
|
||||
- **Email:** moin@linuxcommand.dev
|
||||
- **Subject:** `[SECURITY] NAS Setup Script Vulnerability Report`
|
||||
|
||||
### ⏰ Response Timeline
|
||||
|
||||
We will acknowledge your report within 48 hours and provide a more detailed response within 7 days indicating our next steps.
|
||||
|
||||
We will keep you informed about our progress throughout the process of fixing the vulnerability.
|
||||
|
||||
### 📋 What to Include
|
||||
|
||||
Please include the following information in your report:
|
||||
- A clear description of the vulnerability
|
||||
- Steps to reproduce the issue
|
||||
- Potential impact and severity
|
||||
- Any suggested fixes or mitigations
|
||||
- Your contact information for follow-up
|
||||
|
||||
## 🛡️ Security Considerations
|
||||
|
||||
### Current Security Features
|
||||
|
||||
The NAS Setup Script includes several security measures:
|
||||
|
||||
- **Input Validation:** Comprehensive validation of all user inputs
|
||||
- **SSH Hardening:** Ed25519 key generation and secure configurations
|
||||
- **Firewall Management:** IPv4/IPv6 firewall rules with UFW/Firewalld
|
||||
- **Intrusion Detection:** Fail2ban integration for brute-force protection
|
||||
- **Audit Logging:** System auditing with auditd
|
||||
- **Access Control:** Mandatory Access Control (AppArmor/SELinux)
|
||||
- **Secure Defaults:** Conservative security settings by default
|
||||
- **Distribution Detection:** Robust 5-method fallback system with container environment detection
|
||||
- **Version Validation:** Advanced regex parsing and bc calculator for precise version comparisons
|
||||
- **Unit Testing:** Comprehensive test suite (66+ test cases) ensuring code reliability
|
||||
- **Container Security:** Detection and warnings for Docker/Podman/LXC/WSL environments
|
||||
|
||||
### Known Limitations
|
||||
|
||||
- **Root Access Required:** The script requires root/sudo privileges for system configuration
|
||||
- **Network Dependencies:** Internet access required for package downloads
|
||||
- **Service Exposure:** Configured services may expose ports to networks
|
||||
- **User Responsibility:** End users are responsible for their network security
|
||||
|
||||
## 🔧 Security Updates
|
||||
|
||||
Security updates will be released as patch versions following semantic versioning:
|
||||
- **Critical vulnerabilities:** Immediate patch release
|
||||
- **High severity:** Within 7 days
|
||||
- **Medium/Low severity:** Included in next minor release
|
||||
|
||||
## 📚 Best Practices for Users
|
||||
|
||||
### Before Installation
|
||||
- Review the code and understand what the script does
|
||||
- Test in a virtualized environment first
|
||||
- Backup important data before running
|
||||
- Ensure you have console access in case of issues
|
||||
|
||||
### After Installation
|
||||
- Change default passwords immediately
|
||||
- Review firewall rules and service configurations
|
||||
- Monitor system logs regularly
|
||||
- Keep the system updated with security patches
|
||||
- Use strong, unique passwords for all services
|
||||
|
||||
### Network Security
|
||||
- Place the NAS in a secure network segment
|
||||
- Use VPN for remote access when possible
|
||||
- Implement network segmentation
|
||||
- Regularly audit network access logs
|
||||
|
||||
## 🏷️ Vulnerability Classification
|
||||
|
||||
We use the following severity levels:
|
||||
|
||||
- **Critical:** Remote code execution, privilege escalation, data loss
|
||||
- **High:** Authentication bypass, significant data exposure
|
||||
- **Medium:** Information disclosure, DoS attacks
|
||||
- **Low:** Minor issues with limited impact
|
||||
|
||||
## 🤝 Security Hall of Fame
|
||||
|
||||
We appreciate security researchers who help make this project safer. With your permission, we'll acknowledge your contribution in our security hall of fame.
|
||||
|
||||
## 📞 Contact
|
||||
|
||||
For security-related questions or concerns:
|
||||
- **Security Issues:** Use the reporting process above
|
||||
- **General Security Questions:** Create a GitHub Discussion
|
||||
- **Documentation Issues:** Submit a GitHub Issue
|
||||
|
||||
## 📜 Disclaimer
|
||||
|
||||
This software is provided "as is" without warranty. Users are responsible for their own security practices and should evaluate the suitability of this software for their specific use case.
|
||||
|
||||
---
|
||||
|
||||
*Last updated: October 2025*</content>
|
||||
<parameter name="filePath">/Volumes/homes/sebastian/Projekte/github/nas-main/SECURITY.md
|
||||
@@ -3,7 +3,7 @@
|
||||
# Default configuration values for NAS setup script
|
||||
|
||||
# Script metadata
|
||||
SCRIPT_VERSION="2.0.0"
|
||||
SCRIPT_VERSION="2.1.1"
|
||||
SCRIPT_NAME="NAS Setup Script"
|
||||
SCRIPT_AUTHOR="Sebastian Palencsár"
|
||||
|
||||
@@ -28,7 +28,7 @@ NETDATA_PORT="19999"
|
||||
|
||||
# Docker configuration
|
||||
DEFAULT_DOCKER_DATA_DIR="/var/lib/docker"
|
||||
DOCKER_COMPOSE_VERSION="2.24.0"
|
||||
DOCKER_COMPOSE_VERSION="2.30.0"
|
||||
|
||||
# Application data directories
|
||||
VAULTWARDEN_DATA_DIR="/opt/vaultwarden"
|
||||
@@ -36,14 +36,15 @@ JELLYFIN_DATA_DIR="/var/lib/jellyfin"
|
||||
PORTAINER_DATA_DIR="/opt/portainer"
|
||||
|
||||
# System requirements
|
||||
MIN_DISK_SPACE_GB=20
|
||||
MIN_DISK_SPACE_GB=30
|
||||
MIN_RAM_MB=2048
|
||||
RECOMMENDED_RAM_MB=4096
|
||||
|
||||
# Security settings
|
||||
ENABLE_FAIL2BAN=true
|
||||
ENABLE_UFW=true
|
||||
ENABLE_AUTO_UPDATES=true
|
||||
# Automatic security updates are optional. Default is OFF to keep setup non-interactive.
|
||||
ENABLE_AUTO_UPDATES=false
|
||||
SECURE_SSH=true
|
||||
|
||||
# Debug and logging
|
||||
@@ -65,35 +66,45 @@ NC='\033[0m' # No Color
|
||||
# Supported distributions
|
||||
SUPPORTED_DISTROS=("ubuntu" "debian" "fedora" "arch" "opensuse")
|
||||
|
||||
# Package managers by distribution
|
||||
declare -A PKG_MANAGERS=(
|
||||
["ubuntu"]="apt-get"
|
||||
["debian"]="apt-get"
|
||||
["fedora"]="dnf"
|
||||
["arch"]="pacman"
|
||||
["opensuse"]="zypper"
|
||||
)
|
||||
# Get package manager for distribution
|
||||
get_package_manager() {
|
||||
local distro="$1"
|
||||
case "$distro" in
|
||||
ubuntu|debian) echo "apt-get" ;;
|
||||
fedora) echo "dnf" ;;
|
||||
arch) echo "pacman" ;;
|
||||
opensuse) echo "zypper" ;;
|
||||
*) echo "unknown" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Update commands by distribution
|
||||
declare -A UPDATE_COMMANDS=(
|
||||
["ubuntu"]="apt-get update && apt-get upgrade -y"
|
||||
["debian"]="apt-get update && apt-get upgrade -y"
|
||||
["fedora"]="dnf update -y"
|
||||
["arch"]="pacman -Syu --noconfirm"
|
||||
["opensuse"]="zypper refresh && zypper update -y"
|
||||
)
|
||||
# Get update command for distribution
|
||||
get_update_command() {
|
||||
local distro="$1"
|
||||
case "$distro" in
|
||||
ubuntu|debian) echo "apt-get update && apt-get upgrade -y" ;;
|
||||
fedora) echo "dnf update -y" ;;
|
||||
arch) echo "pacman -Syu --noconfirm" ;;
|
||||
opensuse) echo "zypper refresh && zypper update -y" ;;
|
||||
*) echo "unknown" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Service ports
|
||||
declare -A SERVICE_PORTS=(
|
||||
["ssh"]="${DEFAULT_SSH_PORT}"
|
||||
["samba"]="139,445"
|
||||
["nfs"]="2049"
|
||||
["netdata"]="${NETDATA_PORT}"
|
||||
["vaultwarden"]="8080"
|
||||
["jellyfin"]="8096"
|
||||
["portainer"]="9000"
|
||||
["docker"]="2375,2376"
|
||||
)
|
||||
# Get service port for service
|
||||
get_service_port() {
|
||||
local service="$1"
|
||||
case "$service" in
|
||||
ssh) echo "${DEFAULT_SSH_PORT}" ;;
|
||||
samba) echo "139,445" ;;
|
||||
nfs) echo "2049" ;;
|
||||
netdata) echo "${NETDATA_PORT}" ;;
|
||||
vaultwarden) echo "8080" ;;
|
||||
jellyfin) echo "8096" ;;
|
||||
portainer) echo "9000" ;;
|
||||
docker) echo "2375,2376" ;;
|
||||
*) echo "unknown" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Default firewall rules
|
||||
FIREWALL_RULES=(
|
||||
@@ -111,6 +122,7 @@ INSTALL_NETDATA=${INSTALL_NETDATA:-false}
|
||||
INSTALL_VAULTWARDEN=${INSTALL_VAULTWARDEN:-false}
|
||||
INSTALL_JELLYFIN=${INSTALL_JELLYFIN:-false}
|
||||
INSTALL_PORTAINER=${INSTALL_PORTAINER:-false}
|
||||
INSTALL_WEBMIN=${INSTALL_WEBMIN:-false}
|
||||
|
||||
# Configuration validation
|
||||
validate_config() {
|
||||
@@ -136,5 +148,13 @@ validate_config() {
|
||||
fi
|
||||
done
|
||||
|
||||
# Validate Docker dependencies
|
||||
if [[ "${INSTALL_DOCKER:-false}" != "true" ]]; then
|
||||
if [[ "${INSTALL_VAULTWARDEN:-false}" == "true" ]] || [[ "${INSTALL_JELLYFIN:-false}" == "true" ]] || [[ "${INSTALL_PORTAINER:-false}" == "true" ]]; then
|
||||
log_warning "Docker-abhängige Services sind aktiviert, aber Docker ist deaktiviert. Bitte wähle Docker oder deaktiviere diese Services."
|
||||
((errors++))
|
||||
fi
|
||||
fi
|
||||
|
||||
return $errors
|
||||
}
|
||||
|
||||
159
lib/common.sh
159
lib/common.sh
@@ -198,7 +198,7 @@ check_command() {
|
||||
}
|
||||
|
||||
install_dependencies() {
|
||||
local dependencies=("curl" "wget" "git" "ufw" "htop" "tree")
|
||||
local dependencies=("curl" "wget" "git" "ufw" "htop" "tree" "bc")
|
||||
local missing_deps=()
|
||||
|
||||
log_info "Checking system dependencies..."
|
||||
@@ -260,6 +260,57 @@ start_and_enable_service() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Robust SSH restart helper: try sshd, then ssh, then service command
|
||||
restart_ssh_service() {
|
||||
log_info "Attempting to restart SSH service using available service name..."
|
||||
|
||||
if systemctl list-unit-files --type=service | grep -q "^sshd.service"; then
|
||||
log_info "Found sshd.service, attempting restart..."
|
||||
if sudo systemctl restart sshd 2>&1; then
|
||||
log_success "sshd.service restarted successfully"
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
log_warning "systemctl restart sshd failed with exit code $exit_code"
|
||||
# Check if service is actually running despite the error
|
||||
if sudo systemctl is-active --quiet sshd; then
|
||||
log_success "sshd.service is running despite restart error"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if systemctl list-unit-files --type=service | grep -q "^ssh.service"; then
|
||||
log_info "Found ssh.service, attempting restart..."
|
||||
if sudo systemctl restart ssh 2>&1; then
|
||||
log_success "ssh.service restarted successfully"
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
log_warning "systemctl restart ssh failed with exit code $exit_code"
|
||||
# Check if service is actually running despite the error
|
||||
if sudo systemctl is-active --quiet ssh; then
|
||||
log_success "ssh.service is running despite restart error"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback to service command (deprecated on openSUSE, skip)
|
||||
if [[ "$DISTRO" != "opensuse" ]] && command -v service >/dev/null 2>&1; then
|
||||
log_info "Trying legacy service command..."
|
||||
if sudo service ssh restart 2>&1; then
|
||||
log_success "SSH restarted via service ssh restart"
|
||||
return 0
|
||||
else
|
||||
log_warning "Failed to restart SSH via 'service ssh restart'"
|
||||
fi
|
||||
fi
|
||||
|
||||
log_error "Unable to restart SSH service with known methods"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Configuration management
|
||||
save_config() {
|
||||
local key="$1"
|
||||
@@ -267,7 +318,8 @@ save_config() {
|
||||
|
||||
if [[ -f "${CONFIG_FILE}" ]]; then
|
||||
if grep -q "^${key}=" "${CONFIG_FILE}"; then
|
||||
sed -i "s/^${key}=.*/${key}=${value}/" "${CONFIG_FILE}"
|
||||
# Use sed with proper escaping
|
||||
sed -i.bak "s|^${key}=.*|${key}=${value}|" "${CONFIG_FILE}" && rm -f "${CONFIG_FILE}.bak"
|
||||
else
|
||||
echo "${key}=${value}" >> "${CONFIG_FILE}"
|
||||
fi
|
||||
@@ -289,6 +341,61 @@ load_config() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Ensure a given user exists; if not, offer to create them interactively.
|
||||
# Usage: ensure_user_exists_interactive <username>
|
||||
ensure_user_exists_interactive() {
|
||||
local user="$1"
|
||||
|
||||
if id -u "$user" >/dev/null 2>&1; then
|
||||
log_debug "User '$user' already exists"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_warning "User '$user' does not exist on this system."
|
||||
if ! ask_yes_no "Create user '$user' now?" "y"; then
|
||||
log_info "Skipping creation of user '$user'. Some features may require this user to exist."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Create user and set password interactively
|
||||
log_info "Creating user '$user'..."
|
||||
if sudo useradd -m -s /bin/bash "$user"; then
|
||||
log_success "User '$user' created"
|
||||
# Add to sudo group
|
||||
sudo usermod -aG sudo "$user" || true
|
||||
|
||||
# Optionally add to docker group if requested or if Docker is to be installed
|
||||
local add_docker_default="n"
|
||||
if [[ "${INSTALL_DOCKER:-false}" == "true" ]]; then
|
||||
add_docker_default="y"
|
||||
fi
|
||||
|
||||
if ask_yes_no "Add user '$user' to 'docker' group?" "$add_docker_default"; then
|
||||
sudo usermod -aG docker "$user" || true
|
||||
# add rollback action for docker group removal
|
||||
if declare -F add_rollback_action >/dev/null 2>&1; then
|
||||
add_rollback_action "sudo gpasswd -d $user docker || true"
|
||||
fi
|
||||
log_info "User '$user' added to docker group"
|
||||
fi
|
||||
|
||||
# Ask for password
|
||||
local pw
|
||||
pw=$(ask_password "Set password for user $user")
|
||||
echo "$user:$pw" | sudo chpasswd
|
||||
|
||||
# Record rollback action for user deletion
|
||||
if declare -F add_rollback_action >/dev/null 2>&1; then
|
||||
add_rollback_action "sudo userdel -r $user || true"
|
||||
fi
|
||||
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to create user '$user'"
|
||||
return 2
|
||||
fi
|
||||
}
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
log_info "Performing cleanup..."
|
||||
@@ -320,20 +427,20 @@ cleanup() {
|
||||
# Performance monitoring
|
||||
get_system_info() {
|
||||
log_info "System Information:"
|
||||
echo " OS: $(lsb_release -d | cut -f2)"
|
||||
echo " OS: ${DISTRO_NAME:-Unknown}"
|
||||
echo " Kernel: $(uname -r)"
|
||||
echo " CPU: $(lscpu | grep 'Model name' | cut -d: -f2 | xargs)"
|
||||
echo " RAM: $(free -h | awk 'NR==2{printf "%s/%s", $3,$2}')"
|
||||
echo " Disk: $(df -h / | awk 'NR==2{printf "%s/%s (%s used)", $3,$2,$5}')"
|
||||
echo " Uptime: $(uptime -p)"
|
||||
echo " Uptime: $(uptime | awk -F'up ' '{print $2}' | awk -F',' '{print $1,$2}' | xargs)"
|
||||
}
|
||||
|
||||
# Version and compatibility checks
|
||||
check_ubuntu_version() {
|
||||
if [[ "$DISTRO" == "ubuntu" ]]; then
|
||||
local version_major=$(echo "$DISTRO_VERSION" | cut -d'.' -f1)
|
||||
if [[ $version_major -lt 20 ]]; then
|
||||
log_warning "Ubuntu version $DISTRO_VERSION is not officially supported. Minimum: 20.04"
|
||||
if [[ $version_major -lt 24 ]]; then
|
||||
log_warning "Ubuntu version $DISTRO_VERSION is not officially supported. Minimum: 24.04"
|
||||
if ! ask_yes_no "Continue anyway?" "n"; then
|
||||
exit 1
|
||||
fi
|
||||
@@ -403,6 +510,46 @@ setup_basic_monitoring() {
|
||||
log_success "Basic monitoring tools installed"
|
||||
}
|
||||
|
||||
# Preflight: check for running apt/dpkg processes and leftover locks, attempt safe cleanup
|
||||
preflight_apt_cleanup() {
|
||||
log_info "Checking for running apt/dpkg processes and lock files..."
|
||||
|
||||
# List processes matching common package manager names
|
||||
local procs
|
||||
procs=$(pgrep -a -f "apt-get|apt|dpkg|unattended-upgrade|aptitude" 2>/dev/null || true)
|
||||
if [[ -n "$procs" ]]; then
|
||||
log_warning "Found running package processes:"
|
||||
echo "$procs"
|
||||
log_info "Waiting up to 15s for them to finish gracefully..."
|
||||
for i in {1..15}; do
|
||||
sleep 1
|
||||
if ! pgrep -f "apt-get|apt|dpkg|unattended-upgrade|aptitude" >/dev/null; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if pgrep -f "apt-get|apt|dpkg|unattended-upgrade|aptitude" >/dev/null; then
|
||||
log_warning "Package processes still running; attempting graceful stop..."
|
||||
sudo pkill -15 -f "apt-get|apt|unattended-upgrade|aptitude" || true
|
||||
sleep 2
|
||||
if pgrep -f "apt-get|apt|dpkg|unattended-upgrade|aptitude" >/dev/null; then
|
||||
log_warning "Forcing kill of remaining package processes..."
|
||||
sudo pkill -9 -f "apt-get|apt|dpkg|unattended-upgrade|aptitude" || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove common lock files if present (safe to remove if processes are gone)
|
||||
sudo rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock /var/cache/apt/archives/lock /var/lib/apt/lists/lock || true
|
||||
|
||||
# Try to finish interrupted package configuration
|
||||
log_info "Running 'dpkg --configure -a' and 'apt-get -f install' (non-interactive) to fix package state..."
|
||||
sudo dpkg --configure -a || true
|
||||
sudo env DEBIAN_FRONTEND=noninteractive APT_LISTCHANGES_FRONTEND=none apt-get -y -f install || true
|
||||
|
||||
log_success "Apt/dpkg preflight cleanup completed"
|
||||
}
|
||||
|
||||
# Install additional components
|
||||
install_additional_components() {
|
||||
log_info "Installing additional useful components..."
|
||||
|
||||
132
lib/detection.sh
Normal file
132
lib/detection.sh
Normal file
@@ -0,0 +1,132 @@
|
||||
# Distribution Detection Functions
|
||||
# This file contains functions for detecting Linux distributions and versions
|
||||
|
||||
# Normalize version strings for consistent comparison
|
||||
normalize_version() {
|
||||
local version="$1"
|
||||
|
||||
# Handle common version formats - keep original format but ensure x.y.z structure
|
||||
if [[ $version =~ ^([0-9]+)(\.([0-9]+))?(\.([0-9]+))?.* ]]; then
|
||||
# Standard x.y.z format - ensure all parts exist
|
||||
local major="${BASH_REMATCH[1]}"
|
||||
local minor="${BASH_REMATCH[3]:-0}"
|
||||
local patch="${BASH_REMATCH[5]:-0}"
|
||||
echo "${major}.${minor}.${patch}"
|
||||
elif [[ $version =~ ^([0-9]+)\.([0-9]+)[[:space:]]*\((.*)\)$ ]]; then
|
||||
# Debian style: "12 (bookworm)" -> "12.0.0"
|
||||
echo "${BASH_REMATCH[1]}.0.0"
|
||||
elif [[ $version == "rolling" ]] || [[ $version == "unstable" ]]; then
|
||||
# Rolling releases
|
||||
echo "9999.0.0" # High version number for rolling releases
|
||||
else
|
||||
# Fallback: try to extract first number
|
||||
local num_version=$(echo "$version" | grep -oP '\d+(\.\d+)*' | head -1)
|
||||
if [[ -n "$num_version" ]]; then
|
||||
echo "$num_version"
|
||||
else
|
||||
echo "0.0.0"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Version comparison function using bc for reliability
|
||||
version_compare() {
|
||||
local version1="$1"
|
||||
local operator="$2"
|
||||
local version2="$3"
|
||||
|
||||
# Convert versions to comparable format
|
||||
local v1_num=$(echo "$version1" | tr '.' ' ' | awk '{printf "%d%02d%02d", $1, $2, $3}')
|
||||
local v2_num=$(echo "$version2" | tr '.' ' ' | awk '{printf "%d%02d%02d", $1, $2, $3}')
|
||||
|
||||
case $operator in
|
||||
">=") [[ $v1_num -ge $v2_num ]] ;;
|
||||
">") [[ $v1_num -gt $v2_num ]] ;;
|
||||
"<=") [[ $v1_num -le $v2_num ]] ;;
|
||||
"<") [[ $v1_num -lt $v2_num ]] ;;
|
||||
"="|"==") [[ $v1_num -eq $v2_num ]] ;;
|
||||
"!=") [[ $v1_num -ne $v2_num ]] ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Validate minimum version requirements
|
||||
validate_minimum_version() {
|
||||
local distro="$1"
|
||||
local version="$2"
|
||||
|
||||
case $distro in
|
||||
ubuntu)
|
||||
if ! version_compare "$version" ">=" "24.04.0"; then
|
||||
log_warning "Ubuntu version $version is below minimum requirement (24.04)"
|
||||
log_warning "Some features may not work correctly"
|
||||
fi
|
||||
;;
|
||||
debian)
|
||||
if ! version_compare "$version" ">=" "12.0.0"; then
|
||||
log_warning "Debian version $version is below minimum requirement (12)"
|
||||
log_warning "Some features may not work correctly"
|
||||
fi
|
||||
;;
|
||||
fedora)
|
||||
if ! version_compare "$version" ">=" "41.0.0"; then
|
||||
log_warning "Fedora version $version is below minimum requirement (41)"
|
||||
log_warning "Some features may not work correctly"
|
||||
fi
|
||||
;;
|
||||
opensuse)
|
||||
if ! version_compare "$version" ">=" "15.6.0"; then
|
||||
log_warning "openSUSE version $version is below minimum requirement (15.6)"
|
||||
log_warning "Some features may not work correctly"
|
||||
fi
|
||||
;;
|
||||
arch)
|
||||
# Arch is rolling, always considered compatible
|
||||
log_debug "Arch Linux rolling release detected - fully supported"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Detect container environments that might affect behavior
|
||||
detect_container_environment() {
|
||||
local container_type=""
|
||||
|
||||
# Docker container detection
|
||||
if [[ -f /.dockerenv ]] || grep -q docker /proc/1/cgroup 2>/dev/null; then
|
||||
container_type="docker"
|
||||
log_debug "Running inside Docker container"
|
||||
fi
|
||||
|
||||
# Podman container detection
|
||||
if [[ -f /.podmanenv ]] || grep -q podman /proc/1/cgroup 2>/dev/null; then
|
||||
container_type="podman"
|
||||
log_debug "Running inside Podman container"
|
||||
fi
|
||||
|
||||
# LXC/LXD detection
|
||||
if [[ -f /proc/1/environ ]] && grep -q lxc /proc/1/environ 2>/dev/null; then
|
||||
container_type="lxc"
|
||||
log_debug "Running inside LXC container"
|
||||
fi
|
||||
|
||||
# WSL detection
|
||||
if grep -q Microsoft /proc/version 2>/dev/null || [[ -f /proc/version ]] && grep -q WSL /proc/version; then
|
||||
container_type="wsl"
|
||||
log_debug "Running inside Windows Subsystem for Linux (WSL)"
|
||||
fi
|
||||
|
||||
if [[ -n "$container_type" ]]; then
|
||||
log_info "Container environment detected: $container_type"
|
||||
export CONTAINER_TYPE="$container_type"
|
||||
|
||||
# Adjust behavior for containers
|
||||
case $container_type in
|
||||
docker|podman|lxc)
|
||||
log_warning "Running in container - some system-level features may be limited"
|
||||
;;
|
||||
wsl)
|
||||
log_warning "Running in WSL - Windows integration features may be limited"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
227
lib/docker.sh
227
lib/docker.sh
@@ -1,56 +1,182 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Provide a safe default for SUDO in case the environment or caller
|
||||
# expects a SUDO variable. Some systems or callers may unset this and
|
||||
# scripts using `${SUDO}` should not fail with unbound variable under
|
||||
# `set -u`.
|
||||
SUDO=${SUDO:-sudo}
|
||||
|
||||
# Ensure DOCKER_DATA_DIR has a sensible default to avoid unbound variable
|
||||
# errors when running under `set -u` and when no custom value is provided
|
||||
# by the configuration file. Use DEFAULT_DOCKER_DATA_DIR from defaults.sh.
|
||||
DOCKER_DATA_DIR=${DOCKER_DATA_DIR:-${DEFAULT_DOCKER_DATA_DIR:-/var/lib/docker}}
|
||||
|
||||
install_docker() {
|
||||
log_info "Installing Docker..."
|
||||
|
||||
# Update package index and install prerequisites
|
||||
handle_error sudo apt-get update
|
||||
handle_error sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
|
||||
|
||||
# Add Docker's official GPG key
|
||||
handle_error curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
|
||||
|
||||
# Add Docker's official APT repository
|
||||
handle_error sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
|
||||
|
||||
# Update package index again
|
||||
handle_error sudo apt-get update
|
||||
|
||||
# Install Docker CE
|
||||
handle_error sudo apt-get install -y docker-ce
|
||||
|
||||
# Add user to the docker group
|
||||
handle_error sudo usermod -aG docker "$NEW_USER"
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
handle_error sudo apt-get install -y docker.io
|
||||
# Update package index and install prerequisites
|
||||
handle_error sudo apt-get update
|
||||
handle_error sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
|
||||
|
||||
# Add Docker's official GPG key
|
||||
handle_error curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||
|
||||
# Add Docker's official APT repository
|
||||
handle_error echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
|
||||
# Update package index again
|
||||
handle_error sudo apt-get update
|
||||
|
||||
# Install Docker CE and Compose plugin
|
||||
handle_error sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
;;
|
||||
fedora)
|
||||
handle_error sudo dnf install -y docker
|
||||
# Add Docker repository
|
||||
handle_error sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
|
||||
|
||||
# Install Docker CE
|
||||
handle_error sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
;;
|
||||
arch)
|
||||
handle_error sudo pacman -S --noconfirm docker
|
||||
# Install Docker from official Arch repos (usually up-to-date)
|
||||
handle_error sudo pacman -S --noconfirm docker docker-compose
|
||||
;;
|
||||
opensuse)
|
||||
handle_error sudo zypper install -y docker
|
||||
# Install Docker from official openSUSE repositories
|
||||
# Docker CE is not officially supported on openSUSE, use community packages
|
||||
handle_error sudo zypper install -y docker docker-compose
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported Linux distribution: $DISTRO"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
handle_error sudo systemctl enable docker
|
||||
handle_error sudo systemctl start docker
|
||||
|
||||
# Configure Docker data directory
|
||||
# Determine which user to add to the docker group.
|
||||
# Prefer ADMIN_USER if configured, then NEW_USER. If neither exists,
|
||||
# try to auto-detect a suitable non-root sudo-capable user. Only create
|
||||
# a new user if CREATE_NEW_USER_IF_MISSING=true.
|
||||
TARGET_USER=""
|
||||
|
||||
if [[ -n "${ADMIN_USER:-}" ]] && id -u "${ADMIN_USER}" >/dev/null 2>&1; then
|
||||
TARGET_USER="${ADMIN_USER}"
|
||||
log_debug "Using ADMIN_USER='$TARGET_USER' for docker group"
|
||||
elif [[ -n "${NEW_USER:-}" ]] && id -u "${NEW_USER}" >/dev/null 2>&1; then
|
||||
TARGET_USER="${NEW_USER}"
|
||||
log_debug "Using NEW_USER='$TARGET_USER' for docker group"
|
||||
else
|
||||
# Gather human non-system users (UID >= 1000) with a normal shell
|
||||
mapfile -t _candidates < <(awk -F: '($3>=1000 && $7!="/usr/sbin/nologin" && $7!="/bin/false"){print $1}' /etc/passwd | sort)
|
||||
|
||||
if [[ ${#_candidates[@]} -eq 1 ]]; then
|
||||
TARGET_USER="${_candidates[0]}"
|
||||
log_info "Auto-detected user '$TARGET_USER' to add to docker group"
|
||||
elif [[ ${#_candidates[@]} -gt 1 ]]; then
|
||||
log_info "Multiple candidate user accounts found. Please choose which to add to the docker group:"
|
||||
local i=0
|
||||
for u in "${_candidates[@]}"; do
|
||||
i=$((i+1))
|
||||
if id -nG "$u" 2>/dev/null | grep -qw sudo; then
|
||||
echo " $i) $u (sudo)"
|
||||
else
|
||||
echo " $i) $u"
|
||||
fi
|
||||
done
|
||||
echo " 0) None / create new user"
|
||||
|
||||
# Ask until valid selection
|
||||
local sel
|
||||
while true; do
|
||||
sel=$(ask_input "Select user number to add to docker group (0 to skip)" "1" )
|
||||
if [[ "$sel" =~ ^[0-9]+$ ]] && [[ "$sel" -ge 0 ]] && [[ "$sel" -le ${#_candidates[@]} ]]; then
|
||||
break
|
||||
fi
|
||||
log_warning "Please enter a number between 0 and ${#_candidates[@]}"
|
||||
done
|
||||
|
||||
if [[ "$sel" -eq 0 ]]; then
|
||||
TARGET_USER=""
|
||||
else
|
||||
TARGET_USER="${_candidates[$((sel-1))]}"
|
||||
fi
|
||||
else
|
||||
TARGET_USER=""
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$TARGET_USER" ]]; then
|
||||
handle_error sudo usermod -aG docker "$TARGET_USER"
|
||||
else
|
||||
log_warning "No suitable non-root user found to add to docker group."
|
||||
if [[ "${CREATE_NEW_USER_IF_MISSING:-false}" == "true" ]]; then
|
||||
local create_user
|
||||
create_user="${ADMIN_USER:-${NEW_USER:-nasadmin}}"
|
||||
log_info "Creating user '$create_user' and adding to docker group..."
|
||||
handle_error sudo useradd -m -s /bin/bash "$create_user"
|
||||
handle_error sudo usermod -aG docker "$create_user"
|
||||
fi
|
||||
fi
|
||||
|
||||
handle_error sudo systemctl enable docker
|
||||
|
||||
# Try to start docker; if starting fails, attempt automated repair and retry.
|
||||
# If still failing after retries, disable Docker for the remainder of the setup
|
||||
# to avoid aborting the whole installation (docker-dependent services will be skipped).
|
||||
local _start_retries=2
|
||||
local _attempt=0
|
||||
local _started=false
|
||||
local _repair_script="${SCRIPT_DIR:-$(pwd)}/scripts/repair_docker.sh"
|
||||
|
||||
while [[ $_attempt -lt $_start_retries ]]; do
|
||||
if sudo systemctl start docker; then
|
||||
_started=true
|
||||
log_success "docker.service started successfully"
|
||||
break
|
||||
else
|
||||
log_warning "docker.service failed to start (attempt $(( _attempt + 1 ))/$_start_retries)"
|
||||
if [[ -x "$_repair_script" ]]; then
|
||||
log_info "Running repair script $_repair_script to fix docker configuration..."
|
||||
sudo bash "$_repair_script" || log_warning "Repair script exited with non-zero status"
|
||||
else
|
||||
log_info "Repair script not found at $_repair_script; attempting local repair via configure_docker_daemon if available"
|
||||
if declare -F configure_docker_daemon >/dev/null 2>&1; then
|
||||
configure_docker_daemon || log_warning "configure_docker_daemon returned non-zero"
|
||||
fi
|
||||
fi
|
||||
sleep 2
|
||||
fi
|
||||
_attempt=$((_attempt + 1))
|
||||
done
|
||||
|
||||
if [[ "$_started" != true ]]; then
|
||||
log_error "docker.service failed to start after $_start_retries attempts."
|
||||
# If running interactively, ask whether to continue without Docker or abort.
|
||||
if [[ -t 0 ]]; then
|
||||
if ask_yes_no "Docker failed to start. Continue setup without Docker (skip Docker-dependent services)?" "y"; then
|
||||
log_warning "Continuing setup without Docker. Docker-dependent services will be skipped."
|
||||
INSTALL_DOCKER=false
|
||||
else
|
||||
log_error "Aborting setup because Docker could not be started and user chose to abort."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Non-interactive environment: default to continuing without Docker to avoid blocking
|
||||
log_warning "Non-interactive shell detected - continuing setup without Docker."
|
||||
INSTALL_DOCKER=false
|
||||
fi
|
||||
fi
|
||||
|
||||
# Configure Docker data directory and optimization
|
||||
if [[ "$DOCKER_DATA_DIR" != "$DEFAULT_DOCKER_DATA_DIR" ]]; then
|
||||
log_info "Configuring Docker data directory to $DOCKER_DATA_DIR..."
|
||||
handle_error sudo mkdir -p "$DOCKER_DATA_DIR"
|
||||
echo "{\"data-root\": \"$DOCKER_DATA_DIR\"}" | sudo tee /etc/docker/daemon.json > /dev/null
|
||||
handle_error sudo systemctl restart docker
|
||||
fi
|
||||
|
||||
|
||||
# Create optimized Docker daemon configuration
|
||||
configure_docker_daemon
|
||||
|
||||
export DOCKER_CONTENT_TRUST=1
|
||||
|
||||
log_info "Docker installed successfully."
|
||||
@@ -66,3 +192,46 @@ install_docker() {
|
||||
echo "5. Enable linger for the user:"
|
||||
echo " sudo loginctl enable-linger \$(whoami)"
|
||||
}
|
||||
|
||||
# Configure optimized Docker daemon
|
||||
configure_docker_daemon() {
|
||||
log_info "Configuring optimized Docker daemon..."
|
||||
|
||||
sudo mkdir -p /etc/docker
|
||||
|
||||
# Create optimized daemon.json with optional data-root
|
||||
local _data_root_line=""
|
||||
if [[ "$DOCKER_DATA_DIR" != "${DEFAULT_DOCKER_DATA_DIR}" ]]; then
|
||||
_data_root_line=" \"data-root\": \"${DOCKER_DATA_DIR}\","
|
||||
log_debug "Including data-root in daemon.json: ${DOCKER_DATA_DIR}"
|
||||
fi
|
||||
|
||||
sudo tee /etc/docker/daemon.json > /dev/null <<EOF
|
||||
{
|
||||
${_data_root_line}
|
||||
"storage-driver": "overlay2",
|
||||
"log-driver": "json-file",
|
||||
"log-opts": {
|
||||
"max-size": "10m",
|
||||
"max-file": "3"
|
||||
},
|
||||
"exec-opts": ["native.cgroupdriver=systemd"],
|
||||
"live-restore": true,
|
||||
"userland-proxy": false,
|
||||
"experimental": false,
|
||||
"metrics-addr": "0.0.0.0:9323",
|
||||
"default-ulimits": {
|
||||
"nofile": {
|
||||
"Name": "nofile",
|
||||
"Soft": 64000,
|
||||
"Hard": 64000
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Restart Docker to apply configuration
|
||||
handle_error sudo systemctl restart docker
|
||||
|
||||
log_success "Docker daemon optimized"
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ configure_ufw() {
|
||||
# Reset UFW to defaults
|
||||
sudo ufw --force reset
|
||||
|
||||
# Enable IPv6 support
|
||||
sudo sed -i 's/IPV6=no/IPV6=yes/' /etc/default/ufw
|
||||
|
||||
# Set default policies
|
||||
sudo ufw default deny incoming
|
||||
sudo ufw default allow outgoing
|
||||
@@ -59,6 +62,10 @@ configure_firewalld() {
|
||||
# Set default zone
|
||||
sudo firewall-cmd --set-default-zone=public
|
||||
|
||||
# Ensure IPv6 support is active (firewalld supports it natively)
|
||||
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" accept'
|
||||
sudo firewall-cmd --reload
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -119,8 +126,12 @@ add_ufw_rules() {
|
||||
|
||||
# Local network communication
|
||||
local local_networks=("192.168.0.0/16" "10.0.0.0/8" "172.16.0.0/12")
|
||||
local local_ipv6_networks=("fe80::/10" "fc00::/7")
|
||||
for network in "${local_networks[@]}"; do
|
||||
sudo ufw allow from "$network" comment "Local network"
|
||||
sudo ufw allow from "$network" comment "Local IPv4 network"
|
||||
done
|
||||
for network in "${local_ipv6_networks[@]}"; do
|
||||
sudo ufw allow from "$network" comment "Local IPv6 network"
|
||||
done
|
||||
|
||||
log_success "UFW rules configured successfully"
|
||||
@@ -177,6 +188,13 @@ add_firewalld_rules() {
|
||||
sudo firewall-cmd --permanent --add-port=8080/tcp
|
||||
fi
|
||||
|
||||
# Local network communication (IPv4 and IPv6)
|
||||
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.0/16" accept'
|
||||
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" accept'
|
||||
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="172.16.0.0/12" accept'
|
||||
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" source address="fe80::/10" accept'
|
||||
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" source address="fc00::/7" accept'
|
||||
|
||||
# Reload firewalld
|
||||
sudo firewall-cmd --reload
|
||||
|
||||
@@ -216,7 +234,7 @@ configure_ip_blocking() {
|
||||
# Create script for manual IP blocking
|
||||
sudo tee /usr/local/bin/block-ip > /dev/null <<'EOF'
|
||||
#!/bin/bash
|
||||
# Script to block IP addresses
|
||||
# Script to block IP addresses (IPv4 and IPv6)
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <IP_ADDRESS>"
|
||||
@@ -225,18 +243,25 @@ fi
|
||||
|
||||
IP="$1"
|
||||
|
||||
# Validate IP address
|
||||
if [[ ! $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
echo "Error: Invalid IP address format"
|
||||
# Validate IP address (IPv4 or IPv6)
|
||||
if [[ ! $IP =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && [[ ! $IP =~ ^([0-9a-fA-F:]+:+)+[0-9a-fA-F]*$ ]]; then
|
||||
echo "Error: Invalid IP address format (IPv4 or IPv6)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine family
|
||||
if [[ $IP =~ : ]]; then
|
||||
FAMILY="ipv6"
|
||||
else
|
||||
FAMILY="ipv4"
|
||||
fi
|
||||
|
||||
# Block IP based on firewall type
|
||||
if command -v ufw &>/dev/null; then
|
||||
ufw deny from "$IP"
|
||||
echo "IP $IP blocked via UFW"
|
||||
elif command -v firewall-cmd &>/dev/null; then
|
||||
firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='$IP' reject"
|
||||
firewall-cmd --permanent --add-rich-rule="rule family='$FAMILY' source address='$IP' reject"
|
||||
firewall-cmd --reload
|
||||
echo "IP $IP blocked via firewalld"
|
||||
else
|
||||
@@ -253,7 +278,7 @@ EOF
|
||||
# Create script for unblocking IP addresses
|
||||
sudo tee /usr/local/bin/unblock-ip > /dev/null <<'EOF'
|
||||
#!/bin/bash
|
||||
# Script to unblock IP addresses
|
||||
# Script to unblock IP addresses (IPv4 and IPv6)
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <IP_ADDRESS>"
|
||||
@@ -262,18 +287,25 @@ fi
|
||||
|
||||
IP="$1"
|
||||
|
||||
# Validate IP address
|
||||
if [[ ! $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
echo "Error: Invalid IP address format"
|
||||
# Validate IP address (IPv4 or IPv6)
|
||||
if [[ ! $IP =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && [[ ! $IP =~ ^([0-9a-fA-F:]+:+)+[0-9a-fA-F]*$ ]]; then
|
||||
echo "Error: Invalid IP address format (IPv4 or IPv6)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine family
|
||||
if [[ $IP =~ : ]]; then
|
||||
FAMILY="ipv6"
|
||||
else
|
||||
FAMILY="ipv4"
|
||||
fi
|
||||
|
||||
# Unblock IP based on firewall type
|
||||
if command -v ufw &>/dev/null; then
|
||||
ufw delete deny from "$IP"
|
||||
echo "IP $IP unblocked via UFW"
|
||||
elif command -v firewall-cmd &>/dev/null; then
|
||||
firewall-cmd --permanent --remove-rich-rule="rule family='ipv4' source address='$IP' reject"
|
||||
firewall-cmd --permanent --remove-rich-rule="rule family='$FAMILY' source address='$IP' reject"
|
||||
firewall-cmd --reload
|
||||
echo "IP $IP unblocked via firewalld"
|
||||
else
|
||||
|
||||
@@ -1,11 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
check_internet_connection() {
|
||||
log_info "Checking internet connection..."
|
||||
if ping -c 1 google.com &> /dev/null; then
|
||||
log_info "Internet connection is active."
|
||||
else
|
||||
log_error "No internet connection. Please check your network settings."
|
||||
log_info "Checking internet connection (IPv4 and IPv6)..."
|
||||
|
||||
local ipv4_hosts=("8.8.8.8" "1.1.1.1" "google.com")
|
||||
local ipv6_hosts=("2001:4860:4860::8888" "2606:4700:4700::1111" "google.com")
|
||||
local success=false
|
||||
|
||||
# Test IPv4
|
||||
for host in "${ipv4_hosts[@]}"; do
|
||||
if ping -c 1 -W 5 "$host" &>/dev/null; then
|
||||
log_success "IPv4 internet connectivity confirmed (via $host)"
|
||||
success=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Test IPv6 if IPv4 failed or to confirm dual-stack
|
||||
if [[ "$success" == false ]] || true; then # Always test IPv6 for completeness
|
||||
for host in "${ipv6_hosts[@]}"; do
|
||||
if ping6 -c 1 -W 5 "$host" &>/dev/null; then
|
||||
log_success "IPv6 internet connectivity confirmed (via $host)"
|
||||
success=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ "$success" == false ]]; then
|
||||
log_error "No internet connection detected (IPv4 or IPv6). Please check your network settings."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Internet connection check completed."
|
||||
}
|
||||
|
||||
@@ -25,14 +25,15 @@ install_jellyfin() {
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
handle_error sudo apt-get update
|
||||
handle_error sudo apt-get install -y apt-transport-https software-properties-common
|
||||
handle_error wget -O - https://repo.jellyfin.org/jellyfin_team.gpg.key | sudo apt-key add -
|
||||
handle_error sudo add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://repo.jellyfin.org/$(lsb_release -cs) main"
|
||||
handle_error sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
|
||||
handle_error curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/jellyfin.gpg
|
||||
handle_error echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/jellyfin.gpg] https://repo.jellyfin.org/$(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/jellyfin.list > /dev/null
|
||||
handle_error sudo apt-get update
|
||||
handle_error sudo apt-get install -y jellyfin
|
||||
;;
|
||||
fedora)
|
||||
handle_error sudo dnf install -y https://repo.jellyfin.org/releases/server/fedora/releases/jellyfin-server.rpm
|
||||
handle_error sudo dnf config-manager --add-repo https://repo.jellyfin.org/releases/server/fedora/jellyfin.repo
|
||||
handle_error sudo dnf install -y jellyfin
|
||||
;;
|
||||
arch)
|
||||
handle_error sudo pacman -S --noconfirm jellyfin
|
||||
@@ -54,12 +55,21 @@ install_jellyfin() {
|
||||
log_info "Jellyfin installation completed."
|
||||
}
|
||||
|
||||
# Detect the distribution and call the appropriate function
|
||||
if [ -f /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
DISTRO=$ID
|
||||
install_jellyfin
|
||||
else
|
||||
log_error "Cannot detect the operating system."
|
||||
exit 1
|
||||
# Logging-Funktionen bereitstellen, falls nicht vorhanden
|
||||
if ! command -v log_info &>/dev/null; then
|
||||
log_info() { echo "[INFO] $1"; }
|
||||
log_error() { echo "[ERROR] $1" >&2; }
|
||||
fi
|
||||
|
||||
# Nur ausführen, wenn diese Datei direkt ausgeführt wird (nicht beim `source` in setup.sh).
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
# Detect the distribution and call the appropriate function
|
||||
if [ -f /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
DISTRO=$ID
|
||||
install_jellyfin
|
||||
else
|
||||
log_error "Cannot detect the operating system."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -5,12 +5,60 @@
|
||||
install_netdata() {
|
||||
log_info "Installing Netdata..."
|
||||
|
||||
# Install dependencies
|
||||
handle_error sudo apt-get update
|
||||
handle_error sudo apt-get install -y curl git
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
# Install dependencies
|
||||
handle_error sudo apt-get update
|
||||
handle_error sudo apt-get install -y curl git
|
||||
;;
|
||||
fedora)
|
||||
# Install dependencies
|
||||
handle_error sudo dnf install -y curl git
|
||||
;;
|
||||
arch)
|
||||
# Install dependencies
|
||||
handle_error sudo pacman -S --noconfirm curl git
|
||||
;;
|
||||
opensuse)
|
||||
# Install dependencies
|
||||
handle_error sudo zypper install -y curl git
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported Linux distribution: $DISTRO"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Install Netdata from GitHub
|
||||
handle_error bash <(curl -Ss https://my-netdata.io/kickstart.sh) --stable-channel --disable-telemetry
|
||||
# Install Netdata using official repository for better reliability
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
# Add Netdata repository
|
||||
handle_error curl -fsSL https://packagecloud.io/netdata/netdata/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/netdata-archive-keyring.gpg
|
||||
handle_error echo "deb [signed-by=/usr/share/keyrings/netdata-archive-keyring.gpg] https://packagecloud.io/netdata/netdata/ubuntu/ noble main" | sudo tee /etc/apt/sources.list.d/netdata.list > /dev/null
|
||||
handle_error sudo apt-get update
|
||||
handle_error sudo apt-get install -y netdata
|
||||
;;
|
||||
fedora)
|
||||
# Add Netdata repository
|
||||
handle_error curl -fsSL https://packagecloud.io/netdata/netdata/gpgkey | sudo rpm --import -
|
||||
handle_error curl -fsSL https://packagecloud.io/install/repositories/netdata/netdata/script.rpm.sh | sudo bash
|
||||
handle_error sudo dnf install -y netdata
|
||||
;;
|
||||
arch)
|
||||
# Install from AUR or official repos if available
|
||||
handle_error sudo pacman -S --noconfirm netdata
|
||||
;;
|
||||
opensuse)
|
||||
# Add Netdata repository (use generic Leap repo)
|
||||
handle_error sudo zypper addrepo -f https://packagecloud.io/netdata/netdata/opensuse/leap netdata
|
||||
handle_error sudo zypper --gpg-auto-import-keys refresh
|
||||
handle_error sudo zypper install -y netdata
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported Linux distribution: $DISTRO"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
handle_error sudo systemctl enable netdata
|
||||
handle_error sudo systemctl start netdata
|
||||
|
||||
@@ -59,7 +59,7 @@ configure_netplan() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Create new netplan configuration
|
||||
# Create new netplan configuration (IPv4 and IPv6)
|
||||
cat <<EOF | sudo tee "$netplan_file" > /dev/null
|
||||
network:
|
||||
version: 2
|
||||
@@ -71,7 +71,7 @@ network:
|
||||
- to: default
|
||||
via: $gateway_ip
|
||||
nameservers:
|
||||
addresses: [$dns_ip, 8.8.8.8]
|
||||
addresses: [$dns_ip, 8.8.8.8, 2001:4860:4860::8888]
|
||||
dhcp4: false
|
||||
dhcp6: false
|
||||
EOF
|
||||
@@ -203,16 +203,16 @@ configure_ssh() {
|
||||
fi
|
||||
|
||||
# Create new user if not exists
|
||||
if ! id "${ADMIN_USER:-$NEW_USER}" &>/dev/null; then
|
||||
log_info "Creating user ${ADMIN_USER:-$NEW_USER}..."
|
||||
sudo useradd -m -s /bin/bash "${ADMIN_USER:-$NEW_USER}"
|
||||
sudo usermod -aG sudo "${ADMIN_USER:-$NEW_USER}"
|
||||
if ! id "${ADMIN_USER:-$USER}" &>/dev/null; then
|
||||
log_info "Creating user ${ADMIN_USER:-$USER}..."
|
||||
sudo useradd -m -s /bin/bash "${ADMIN_USER:-$USER}"
|
||||
sudo usermod -aG sudo "${ADMIN_USER:-$USER}"
|
||||
|
||||
# Set password
|
||||
local password=$(ask_password "Set password for user ${ADMIN_USER:-$NEW_USER}")
|
||||
echo "${ADMIN_USER:-$NEW_USER}:$password" | sudo chpasswd
|
||||
local password=$(ask_password "Set password for user ${ADMIN_USER:-$USER}")
|
||||
echo "${ADMIN_USER:-$USER}:$password" | sudo chpasswd
|
||||
|
||||
add_rollback_action "sudo userdel -r ${ADMIN_USER:-$NEW_USER}"
|
||||
add_rollback_action "sudo userdel -r ${ADMIN_USER:-$USER}"
|
||||
fi
|
||||
|
||||
# Configure SSH hardening
|
||||
@@ -232,7 +232,7 @@ ClientAliveInterval 300
|
||||
ClientAliveCountMax 2
|
||||
MaxAuthTries 3
|
||||
LoginGraceTime 60
|
||||
AllowUsers ${ADMIN_USER:-$NEW_USER}
|
||||
AllowUsers ${ADMIN_USER:-$USER}
|
||||
Protocol 2
|
||||
EOF
|
||||
|
||||
@@ -244,10 +244,9 @@ EOF
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Restart SSH service
|
||||
if sudo systemctl restart sshd; then
|
||||
log_success "SSH service restarted successfully"
|
||||
add_rollback_action "sudo cp ${ssh_config}.bak ${ssh_config} && sudo systemctl restart sshd"
|
||||
# Restart SSH service using helper (handles sshd vs ssh service names)
|
||||
if restart_ssh_service; then
|
||||
add_rollback_action "sudo cp ${ssh_config}.bak ${ssh_config} && restart_ssh_service"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to restart SSH service"
|
||||
@@ -281,7 +280,7 @@ setup_samba() {
|
||||
# Create shared directory
|
||||
local share_dir="/srv/samba/shared"
|
||||
sudo mkdir -p "$share_dir"
|
||||
sudo chown "${ADMIN_USER:-$NEW_USER}:${ADMIN_USER:-$NEW_USER}" "$share_dir"
|
||||
sudo chown "${ADMIN_USER:-$USER}:${ADMIN_USER:-$USER}" "$share_dir"
|
||||
sudo chmod 755 "$share_dir"
|
||||
|
||||
# Configure Samba
|
||||
@@ -309,22 +308,32 @@ setup_samba() {
|
||||
browseable = yes
|
||||
writable = yes
|
||||
guest ok = no
|
||||
valid users = ${ADMIN_USER:-$NEW_USER}
|
||||
valid users = ${ADMIN_USER:-$USER}
|
||||
create mask = 0644
|
||||
directory mask = 0755
|
||||
EOF
|
||||
|
||||
# Add Samba user
|
||||
local samba_password=$(ask_password "Set Samba password for user ${ADMIN_USER:-$NEW_USER}")
|
||||
echo -e "$samba_password\n$samba_password" | sudo smbpasswd -a "${ADMIN_USER:-$NEW_USER}"
|
||||
sudo smbpasswd -e "${ADMIN_USER:-$NEW_USER}"
|
||||
local samba_password=$(ask_password "Set Samba password for user ${ADMIN_USER:-$USER}")
|
||||
echo -e "$samba_password\n$samba_password" | sudo smbpasswd -a "${ADMIN_USER:-$USER}"
|
||||
sudo smbpasswd -e "${ADMIN_USER:-$USER}"
|
||||
|
||||
# Start and enable Samba services
|
||||
sudo systemctl enable smbd nmbd
|
||||
if sudo systemctl restart smbd nmbd; then
|
||||
case $DISTRO in
|
||||
ubuntu|debian|fedora|arch)
|
||||
sudo systemctl enable smbd nmbd
|
||||
sudo systemctl restart smbd nmbd
|
||||
;;
|
||||
opensuse)
|
||||
sudo systemctl enable smb nmb
|
||||
sudo systemctl restart smb nmb
|
||||
;;
|
||||
esac
|
||||
|
||||
if sudo systemctl is-active smb >/dev/null 2>&1 && sudo systemctl is-active nmb >/dev/null 2>&1; then
|
||||
log_success "Samba configured and started successfully"
|
||||
log_info "Shared folder created at: $share_dir"
|
||||
add_rollback_action "sudo systemctl stop smbd nmbd && sudo systemctl disable smbd nmbd"
|
||||
add_rollback_action "sudo systemctl stop smb nmb && sudo systemctl disable smb nmb"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to start Samba services"
|
||||
|
||||
55
lib/nfs.sh
55
lib/nfs.sh
@@ -1,7 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
install_nfs() {
|
||||
log_info "Installing NFS..."
|
||||
log_info "Installing and configuring NFS..."
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
handle_error sudo apt-get install -y nfs-kernel-server
|
||||
@@ -20,5 +21,55 @@ install_nfs() {
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
log_info "NFS installation completed."
|
||||
|
||||
# Create NFS export directory
|
||||
local export_dir="${NFS_EXPORT_DIR:-/srv/nfs}"
|
||||
sudo mkdir -p "$export_dir"
|
||||
sudo chown nobody:nogroup "$export_dir"
|
||||
sudo chmod 755 "$export_dir"
|
||||
|
||||
# Configure NFS exports (clean existing entries for this directory first)
|
||||
local exports_file="/etc/exports"
|
||||
backup_config "$exports_file"
|
||||
|
||||
local export_line="$export_dir *(rw,sync,no_subtree_check,no_root_squash)"
|
||||
|
||||
# Remove any existing entries for this export directory to avoid duplicates
|
||||
if grep -q "^$export_dir " "$exports_file" 2>/dev/null; then
|
||||
sudo sed -i "\#^$export_dir #d" "$exports_file"
|
||||
log_debug "Removed existing NFS export entries for $export_dir"
|
||||
fi
|
||||
|
||||
# Add the new export entry
|
||||
echo "$export_line" | sudo tee -a "$exports_file" > /dev/null
|
||||
log_debug "Added NFS export: $export_line"
|
||||
|
||||
# Export NFS shares
|
||||
handle_error sudo exportfs -a
|
||||
|
||||
# Start and enable NFS services
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
handle_error sudo systemctl enable nfs-kernel-server
|
||||
handle_error sudo systemctl start nfs-kernel-server
|
||||
;;
|
||||
fedora|arch|opensuse)
|
||||
handle_error sudo systemctl enable nfs-server
|
||||
handle_error sudo systemctl start nfs-server
|
||||
;;
|
||||
esac
|
||||
|
||||
# Open firewall for NFS
|
||||
if command -v ufw &>/dev/null; then
|
||||
sudo ufw allow 2049/tcp comment "NFS"
|
||||
sudo ufw allow 111/tcp comment "NFS Portmapper"
|
||||
sudo ufw allow 111/udp comment "NFS Portmapper"
|
||||
elif command -v firewall-cmd &>/dev/null; then
|
||||
sudo firewall-cmd --permanent --add-service=nfs
|
||||
sudo firewall-cmd --permanent --add-service=rpc-bind
|
||||
sudo firewall-cmd --permanent --add-service=mountd
|
||||
sudo firewall-cmd --reload
|
||||
fi
|
||||
|
||||
log_info "NFS installation and configuration completed. Export directory: $export_dir"
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
optimize_system_performance() {
|
||||
log_info "Optimizing system performance..."
|
||||
|
||||
# Memory optimization for NAS workloads
|
||||
configure_memory_optimization
|
||||
|
||||
# Optimize kernel parameters
|
||||
sudo tee -a /etc/sysctl.conf > /dev/null <<EOF
|
||||
|
||||
@@ -38,16 +41,25 @@ EOF
|
||||
# Apply kernel parameters
|
||||
sudo sysctl -p
|
||||
|
||||
# Optimize I/O scheduler for SSDs/HDDs
|
||||
local disk_type=$(lsblk -d -o name,rota | awk 'NR>1 {if($2==0) print "ssd"; else print "hdd"; exit}')
|
||||
local root_disk=$(lsblk -no pkname $(findmnt -n -o source /) | head -n1)
|
||||
|
||||
if [[ "$disk_type" == "ssd" ]]; then
|
||||
echo "mq-deadline" | sudo tee "/sys/block/$root_disk/queue/scheduler" > /dev/null
|
||||
log_info "Optimized I/O scheduler for SSD"
|
||||
# Optimize I/O scheduler for SSDs/HDDs (skip for Btrfs filesystems)
|
||||
local root_fs_type=$(findmnt -n -o fstype /)
|
||||
if [[ "$root_fs_type" == "btrfs" ]]; then
|
||||
log_info "Btrfs filesystem detected - skipping I/O scheduler optimization (Btrfs handles I/O optimization internally)"
|
||||
else
|
||||
echo "bfq" | sudo tee "/sys/block/$root_disk/queue/scheduler" > /dev/null
|
||||
log_info "Optimized I/O scheduler for HDD"
|
||||
local disk_type=$(lsblk -d -o name,rota | awk 'NR>1 {if($2==0) print "ssd"; else print "hdd"; exit}')
|
||||
local root_disk=$(lsblk -no pkname $(findmnt -n -o source / | sed 's/\[.*\]//') | head -n1)
|
||||
|
||||
if [[ -n "$root_disk" ]] && [[ -w "/sys/block/$root_disk/queue/scheduler" ]]; then
|
||||
if [[ "$disk_type" == "ssd" ]]; then
|
||||
echo "mq-deadline" | sudo tee "/sys/block/$root_disk/queue/scheduler" > /dev/null
|
||||
log_info "Optimized I/O scheduler for SSD"
|
||||
else
|
||||
echo "bfq" | sudo tee "/sys/block/$root_disk/queue/scheduler" > /dev/null
|
||||
log_info "Optimized I/O scheduler for HDD"
|
||||
fi
|
||||
else
|
||||
log_warning "Could not determine or access root disk scheduler. Skipping I/O optimization."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create performance monitoring script
|
||||
@@ -56,6 +68,25 @@ EOF
|
||||
log_success "System performance optimized"
|
||||
}
|
||||
|
||||
# Memory optimization for NAS workloads
|
||||
configure_memory_optimization() {
|
||||
log_info "Configuring memory optimization for NAS workloads..."
|
||||
|
||||
cat << EOF | sudo tee /etc/sysctl.d/99-nas-optimization.conf
|
||||
# NAS Memory Optimization for better file caching
|
||||
vm.swappiness=10
|
||||
vm.vfs_cache_pressure=50
|
||||
EOF
|
||||
|
||||
# Apply immediately
|
||||
sudo sysctl -p /etc/sysctl.d/99-nas-optimization.conf
|
||||
|
||||
# Add to rollback
|
||||
add_rollback_action "sudo rm -f /etc/sysctl.d/99-nas-optimization.conf && sudo sysctl -p"
|
||||
|
||||
log_success "Memory optimization configured"
|
||||
}
|
||||
|
||||
# Create performance monitoring script
|
||||
create_performance_monitor() {
|
||||
sudo tee /usr/local/bin/nas-performance > /dev/null <<'EOF'
|
||||
@@ -225,7 +256,14 @@ strict locking = no
|
||||
EOF
|
||||
|
||||
# Restart Samba services
|
||||
sudo systemctl restart smbd nmbd
|
||||
case $DISTRO in
|
||||
ubuntu|debian|fedora|arch)
|
||||
sudo systemctl restart smbd nmbd
|
||||
;;
|
||||
opensuse)
|
||||
sudo systemctl restart smb nmb
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Samba performance optimized"
|
||||
}
|
||||
@@ -259,7 +297,42 @@ perform_health_check() {
|
||||
echo
|
||||
|
||||
echo "=== Service Status ==="
|
||||
for service in ssh sshd smbd nmbd docker netdata; do
|
||||
# Check services based on what was configured/installed
|
||||
local services_to_check=()
|
||||
|
||||
# SSH services (distribution-specific)
|
||||
case $DISTRO in
|
||||
opensuse)
|
||||
services_to_check+=("sshd")
|
||||
;;
|
||||
*)
|
||||
services_to_check+=("ssh" "sshd")
|
||||
;;
|
||||
esac
|
||||
|
||||
# Samba services
|
||||
if [[ "${INSTALL_SAMBA:-true}" == "true" ]]; then
|
||||
case $DISTRO in
|
||||
opensuse)
|
||||
services_to_check+=("smb" "nmb")
|
||||
;;
|
||||
*)
|
||||
services_to_check+=("smbd" "nmbd")
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Docker
|
||||
if [[ "${INSTALL_DOCKER:-false}" == "true" ]]; then
|
||||
services_to_check+=("docker")
|
||||
fi
|
||||
|
||||
# Netdata
|
||||
if [[ "${INSTALL_NETDATA:-false}" == "true" ]]; then
|
||||
services_to_check+=("netdata")
|
||||
fi
|
||||
|
||||
for service in "${services_to_check[@]}"; do
|
||||
if systemctl is-active --quiet "$service" 2>/dev/null; then
|
||||
echo "✅ $service: Active"
|
||||
else
|
||||
@@ -281,10 +354,15 @@ perform_health_check() {
|
||||
echo
|
||||
|
||||
echo "=== Security Status ==="
|
||||
if systemctl is-active --quiet fail2ban; then
|
||||
echo "✅ Fail2ban: Active"
|
||||
# Check Fail2ban if SSH was configured (which includes Fail2ban)
|
||||
if [[ "${CONFIGURE_SSH:-true}" == "true" ]]; then
|
||||
if systemctl is-active --quiet fail2ban; then
|
||||
echo "✅ Fail2ban: Active"
|
||||
else
|
||||
echo "❌ Fail2ban: Inactive"
|
||||
fi
|
||||
else
|
||||
echo "❌ Fail2ban: Inactive"
|
||||
echo "ℹ️ Fail2ban: Not configured"
|
||||
fi
|
||||
echo
|
||||
|
||||
@@ -396,7 +474,14 @@ case "${1:-help}" in
|
||||
restart-services)
|
||||
log_maintenance "Restarting NAS services..."
|
||||
|
||||
for service in smbd nmbd docker netdata; do
|
||||
# Samba services based on distribution
|
||||
if [[ "$DISTRO" == "opensuse" ]]; then
|
||||
samba_services="smb nmb"
|
||||
else
|
||||
samba_services="smbd nmbd"
|
||||
fi
|
||||
|
||||
for service in $samba_services docker netdata; do
|
||||
if systemctl is-enabled "$service" &>/dev/null; then
|
||||
systemctl restart "$service"
|
||||
log_maintenance "Restarted $service"
|
||||
|
||||
131
lib/portainer.sh
131
lib/portainer.sh
@@ -1,82 +1,65 @@
|
||||
#!/bin/bash
|
||||
|
||||
# portainer.sh - Script to install Portainer on various Linux distributions
|
||||
# Portainer installation and configuration script (2025-ready)
|
||||
|
||||
# Function to install Portainer on Ubuntu
|
||||
install_portainer_ubuntu() {
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y docker.io
|
||||
sudo systemctl start docker
|
||||
sudo systemctl enable docker
|
||||
install_portainer() {
|
||||
log_info "Installing Portainer..."
|
||||
|
||||
# Docker muss installiert und aktiv sein
|
||||
if ! command -v docker &>/dev/null; then
|
||||
log_error "Docker ist nicht installiert. Bitte Docker zuerst installieren."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Portainer-Volume anlegen
|
||||
sudo docker volume create portainer_data
|
||||
sudo docker run -d -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
|
||||
|
||||
# Vorherigen Portainer-Container stoppen und entfernen, falls vorhanden
|
||||
if sudo docker ps -a --format '{{.Names}}' | grep -q '^portainer$'; then
|
||||
sudo docker stop portainer || true
|
||||
sudo docker rm portainer || true
|
||||
fi
|
||||
|
||||
# Aktuelles Portainer-Image holen
|
||||
sudo docker pull portainer/portainer-ce:latest
|
||||
|
||||
# Portainer starten (Web: Port 9000, Agent: 8000)
|
||||
sudo docker run -d \
|
||||
--name portainer \
|
||||
--restart=always \
|
||||
-p 9000:9000 \
|
||||
-p 9443:9443 \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v portainer_data:/data \
|
||||
portainer/portainer-ce:latest
|
||||
|
||||
# Warten bis Portainer vollständig gestartet ist
|
||||
log_info "Warten auf Portainer-Initialisierung..."
|
||||
sleep 10
|
||||
|
||||
# Portainer neu starten, um das initiale Security-Timeout zu umgehen
|
||||
log_info "Portainer neu starten, um Security-Timeout zu beheben..."
|
||||
sudo docker restart portainer
|
||||
|
||||
# Kurz warten, bis der Neustart abgeschlossen ist
|
||||
sleep 5
|
||||
|
||||
log_success "Portainer wurde erfolgreich installiert und läuft auf Port 9000 (HTTP) und 9443 (HTTPS)."
|
||||
local ip_address
|
||||
ip_address=$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | head -1 | awk '{print $2}' | cut -d/ -f1)
|
||||
log_info "Portainer ist nun verfügbar unter: https://${ip_address}:9443"
|
||||
}
|
||||
|
||||
# Function to install Portainer on Debian
|
||||
install_portainer_debian() {
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y docker.io
|
||||
sudo systemctl start docker
|
||||
sudo systemctl enable docker
|
||||
sudo docker volume create portainer_data
|
||||
sudo docker run -d -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
|
||||
}
|
||||
# Logging-Funktionen bereitstellen, falls nicht vorhanden
|
||||
if ! command -v log_info &>/dev/null; then
|
||||
log_info() { echo "[INFO] $1"; }
|
||||
log_success() { echo "[SUCCESS] $1"; }
|
||||
log_error() { echo "[ERROR] $1" >&2; }
|
||||
fi
|
||||
|
||||
# Function to install Portainer on Fedora
|
||||
install_portainer_fedora() {
|
||||
sudo dnf -y update
|
||||
sudo dnf -y install docker
|
||||
sudo systemctl start docker
|
||||
sudo systemctl enable docker
|
||||
sudo docker volume create portainer_data
|
||||
sudo docker run -d -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
|
||||
}
|
||||
|
||||
# Function to install Portainer on Arch Linux
|
||||
install_portainer_arch() {
|
||||
sudo pacman -Syu --noconfirm
|
||||
sudo pacman -S --noconfirm docker
|
||||
sudo systemctl start docker
|
||||
sudo systemctl enable docker
|
||||
sudo docker volume create portainer_data
|
||||
sudo docker run -d -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
|
||||
}
|
||||
|
||||
# Function to install Portainer on openSUSE
|
||||
install_portainer_opensuse() {
|
||||
sudo zypper refresh
|
||||
sudo zypper install -y docker
|
||||
sudo systemctl start docker
|
||||
sudo systemctl enable docker
|
||||
sudo docker volume create portainer_data
|
||||
sudo docker run -d -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
|
||||
}
|
||||
|
||||
# Main script logic to detect the distribution and call the appropriate function
|
||||
if [ -f /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
case "$ID" in
|
||||
ubuntu)
|
||||
install_portainer_ubuntu
|
||||
;;
|
||||
debian)
|
||||
install_portainer_debian
|
||||
;;
|
||||
fedora)
|
||||
install_portainer_fedora
|
||||
;;
|
||||
arch)
|
||||
install_portainer_arch
|
||||
;;
|
||||
opensuse)
|
||||
install_portainer_opensuse
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported distribution: $ID"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "Cannot detect the operating system."
|
||||
exit 1
|
||||
# Nur ausführen, wenn diese Datei direkt ausgeführt wird (nicht beim `source` in setup.sh).
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
# Hauptlogik
|
||||
install_portainer
|
||||
exit $?
|
||||
fi
|
||||
310
lib/security.sh
310
lib/security.sh
@@ -1,17 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Security configuration script
|
||||
# Security configuration script (2025-enhanced)
|
||||
|
||||
secure_shared_memory() {
|
||||
log_info "Securing shared memory..."
|
||||
handle_error sudo cp /etc/fstab /etc/fstab.bak
|
||||
echo "tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0" | sudo tee -a /etc/fstab
|
||||
handle_error sudo mount -o remount /run/shm
|
||||
log_info "Shared memory secured."
|
||||
|
||||
# Use /dev/shm for shared memory mount point (more compatible across distributions)
|
||||
echo "tmpfs /dev/shm tmpfs defaults,noexec,nosuid 0 0" | sudo tee -a /etc/fstab
|
||||
|
||||
# Ensure mount point exists
|
||||
sudo mkdir -p /dev/shm
|
||||
|
||||
handle_error sudo mount -o remount /dev/shm
|
||||
log_success "Shared memory secured."
|
||||
}
|
||||
|
||||
install_fail2ban() {
|
||||
log_info "Installing Fail2Ban..."
|
||||
log_info "Installing and configuring Fail2Ban..."
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
handle_error sudo apt-get update
|
||||
@@ -25,13 +31,305 @@ install_fail2ban() {
|
||||
;;
|
||||
opensuse)
|
||||
handle_error sudo zypper install -y fail2ban
|
||||
# On openSUSE, create a basic log file for Fail2ban to monitor
|
||||
sudo touch /var/log/fail2ban.log
|
||||
sudo chmod 644 /var/log/fail2ban.log
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported Linux distribution: $DISTRO"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Backup default config
|
||||
backup_config /etc/fail2ban/jail.local
|
||||
|
||||
# Configure Fail2Ban for SSH and other services
|
||||
sudo tee /etc/fail2ban/jail.local > /dev/null <<EOF
|
||||
[DEFAULT]
|
||||
bantime = 3600
|
||||
findtime = 600
|
||||
maxretry = 3
|
||||
|
||||
[sshd]
|
||||
enabled = true
|
||||
port = ${DEFAULT_SSH_PORT:-22}
|
||||
EOF
|
||||
|
||||
# Configure backend based on distribution
|
||||
case $DISTRO in
|
||||
opensuse)
|
||||
# Use journald backend for openSUSE
|
||||
echo "backend = systemd" | sudo tee -a /etc/fail2ban/jail.local
|
||||
echo "journalmatch = _SYSTEMD_UNIT=sshd.service" | sudo tee -a /etc/fail2ban/jail.local
|
||||
;;
|
||||
*)
|
||||
# Use systemd backend for other distributions
|
||||
echo "backend = systemd" | sudo tee -a /etc/fail2ban/jail.local
|
||||
;;
|
||||
esac
|
||||
|
||||
sudo tee -a /etc/fail2ban/jail.local > /dev/null <<EOF
|
||||
EOF
|
||||
|
||||
# Add distribution-specific log path for SSH
|
||||
case $DISTRO in
|
||||
ubuntu|debian|fedora|arch)
|
||||
echo "logpath = /var/log/auth.log" | sudo tee -a /etc/fail2ban/jail.local
|
||||
;;
|
||||
opensuse)
|
||||
# openSUSE uses /var/log/messages for SSH logs
|
||||
echo "logpath = /var/log/messages" | sudo tee -a /etc/fail2ban/jail.local
|
||||
;;
|
||||
*)
|
||||
echo "logpath = /var/log/auth.log" | sudo tee -a /etc/fail2ban/jail.local
|
||||
;;
|
||||
esac
|
||||
|
||||
sudo tee -a /etc/fail2ban/jail.local > /dev/null <<EOF
|
||||
|
||||
[dropbear]
|
||||
enabled = false
|
||||
|
||||
[selinux-ssh]
|
||||
enabled = false
|
||||
|
||||
[nginx-http-auth]
|
||||
enabled = false
|
||||
|
||||
[nginx-noscript]
|
||||
enabled = false
|
||||
|
||||
[nginx-badbots]
|
||||
enabled = false
|
||||
|
||||
[nginx-noproxy]
|
||||
enabled = false
|
||||
|
||||
[nginx-req-limit]
|
||||
enabled = false
|
||||
|
||||
[nginx-botsearch]
|
||||
enabled = false
|
||||
|
||||
[phpmyadmin-syslog]
|
||||
enabled = false
|
||||
|
||||
[roundcube-auth]
|
||||
enabled = false
|
||||
|
||||
[openhab-auth]
|
||||
enabled = false
|
||||
|
||||
[squid]
|
||||
enabled = false
|
||||
|
||||
[nginx-ddos]
|
||||
enabled = false
|
||||
|
||||
[recidive]
|
||||
enabled = true
|
||||
logpath = /var/log/fail2ban.log
|
||||
EOF
|
||||
|
||||
handle_error sudo systemctl enable fail2ban
|
||||
handle_error sudo systemctl start fail2ban
|
||||
log_info "Fail2Ban installation completed."
|
||||
log_success "Fail2Ban installation and configuration completed."
|
||||
}
|
||||
|
||||
# Harden SSH configuration
|
||||
harden_ssh() {
|
||||
log_info "Hardening SSH configuration..."
|
||||
|
||||
local ssh_config="/etc/ssh/sshd_config"
|
||||
backup_config "$ssh_config"
|
||||
|
||||
# Apply security hardening
|
||||
sudo sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' "$ssh_config"
|
||||
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' "$ssh_config"
|
||||
sudo sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' "$ssh_config"
|
||||
sudo sed -i 's/#AuthorizedKeysFile/AuthorizedKeysFile/' "$ssh_config"
|
||||
sudo sed -i 's/#PermitEmptyPasswords no/PermitEmptyPasswords no/' "$ssh_config"
|
||||
sudo sed -i 's/#ChallengeResponseAuthentication no/ChallengeResponseAuthentication no/' "$ssh_config"
|
||||
sudo sed -i 's/#UsePAM yes/UsePAM yes/' "$ssh_config"
|
||||
sudo sed -i 's/#X11Forwarding yes/X11Forwarding no/' "$ssh_config"
|
||||
sudo sed -i 's/#ClientAliveInterval 0/ClientAliveInterval 300/' "$ssh_config"
|
||||
sudo sed -i 's/#ClientAliveCountMax 3/ClientAliveCountMax 2/' "$ssh_config"
|
||||
sudo sed -i 's/#MaxAuthTries 6/MaxAuthTries 3/' "$ssh_config"
|
||||
sudo sed -i 's/#LoginGraceTime 2m/LoginGraceTime 60/' "$ssh_config"
|
||||
sudo sed -i 's/#Protocol 2/Protocol 2/' "$ssh_config"
|
||||
|
||||
# Test SSH config
|
||||
if sudo sshd -t; then
|
||||
if restart_ssh_service; then
|
||||
log_success "SSH hardened successfully."
|
||||
else
|
||||
log_warning "SSH configuration valid but failed to restart service via known methods."
|
||||
fi
|
||||
else
|
||||
log_error "SSH configuration invalid. Restoring backup."
|
||||
sudo cp "${ssh_config}.bak" "$ssh_config"
|
||||
restart_ssh_service || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Configure AppArmor/SELinux
|
||||
configure_mandatory_access_control() {
|
||||
log_info "Configuring Mandatory Access Control..."
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
# AppArmor
|
||||
if command -v apparmor_status &>/dev/null; then
|
||||
sudo systemctl enable apparmor
|
||||
sudo systemctl start apparmor
|
||||
log_success "AppArmor enabled."
|
||||
else
|
||||
log_warning "AppArmor not available."
|
||||
fi
|
||||
;;
|
||||
fedora|opensuse)
|
||||
# SELinux
|
||||
if command -v setenforce &>/dev/null; then
|
||||
sudo setenforce 1
|
||||
sudo sed -i 's/SELINUX=permissive/SELINUX=enforcing/' /etc/selinux/config
|
||||
log_success "SELinux enabled in enforcing mode."
|
||||
else
|
||||
log_warning "SELinux not available."
|
||||
fi
|
||||
;;
|
||||
arch)
|
||||
# AppArmor on Arch (optional)
|
||||
if pacman -Q apparmor &>/dev/null; then
|
||||
sudo systemctl enable apparmor
|
||||
sudo systemctl start apparmor
|
||||
log_success "AppArmor enabled on Arch."
|
||||
else
|
||||
log_info "AppArmor not installed on Arch. Consider installing for better security."
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
log_warning "Mandatory Access Control not configured for $DISTRO."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Install and configure auditd
|
||||
install_auditd() {
|
||||
log_info "Installing and configuring auditd..."
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
handle_error sudo apt-get install -y auditd audispd-plugins
|
||||
;;
|
||||
fedora)
|
||||
handle_error sudo dnf install -y audit audit-libs
|
||||
;;
|
||||
arch)
|
||||
handle_error sudo pacman -S --noconfirm audit
|
||||
;;
|
||||
opensuse)
|
||||
handle_error sudo zypper install -y audit
|
||||
;;
|
||||
*)
|
||||
log_error "auditd not supported on $DISTRO"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Configure audit rules
|
||||
sudo tee -a /etc/audit/rules.d/audit.rules > /dev/null <<EOF
|
||||
# NAS Security Audit Rules
|
||||
-w /etc/passwd -p wa -k passwd_changes
|
||||
-w /etc/shadow -p wa -k shadow_changes
|
||||
-w /etc/group -p wa -k group_changes
|
||||
-w /etc/sudoers -p wa -k sudoers_changes
|
||||
-w /var/log/auth.log -p wa -k auth_logs
|
||||
-w /var/log/sudo.log -p wa -k sudo_logs
|
||||
-a always,exit -F arch=b64 -S execve -F key=executed_commands
|
||||
EOF
|
||||
|
||||
handle_error sudo systemctl enable auditd
|
||||
handle_error sudo systemctl start auditd
|
||||
log_success "auditd installed and configured."
|
||||
}
|
||||
|
||||
# Disable unnecessary services
|
||||
disable_unnecessary_services() {
|
||||
log_info "Disabling unnecessary services..."
|
||||
|
||||
local services_to_disable=("cups" "bluetooth" "avahi-daemon" "ModemManager")
|
||||
|
||||
for service in "${services_to_disable[@]}"; do
|
||||
if systemctl list-unit-files --type=service | grep -q "^${service}.service"; then
|
||||
sudo systemctl disable "$service" 2>/dev/null || true
|
||||
sudo systemctl stop "$service" 2>/dev/null || true
|
||||
log_info "Disabled service: $service"
|
||||
fi
|
||||
done
|
||||
|
||||
log_success "Unnecessary services disabled."
|
||||
}
|
||||
|
||||
# Configure automatic security updates
|
||||
configure_security_updates() {
|
||||
log_info "Configuring automatic security updates..."
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
handle_error sudo apt-get install -y unattended-upgrades
|
||||
sudo dpkg-reconfigure -plow unattended-upgrades
|
||||
;;
|
||||
fedora)
|
||||
handle_error sudo dnf install -y dnf-automatic
|
||||
sudo systemctl enable --now dnf-automatic-install.timer
|
||||
;;
|
||||
arch)
|
||||
log_info "Arch Linux: Security updates via pacman -Syu recommended"
|
||||
;;
|
||||
opensuse)
|
||||
handle_error sudo zypper install -y yast2-online-update-configuration
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Automatic security updates configured."
|
||||
}
|
||||
|
||||
# Generate SSH keys for admin user
|
||||
generate_ssh_keys() {
|
||||
local user="${ADMIN_USER:-$NEW_USER}"
|
||||
local ssh_dir="/home/$user/.ssh"
|
||||
|
||||
if [[ -z "$user" ]]; then
|
||||
log_warning "No admin user defined, skipping SSH key generation."
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Generating SSH keys for user $user..."
|
||||
|
||||
sudo mkdir -p "$ssh_dir"
|
||||
sudo chown "$user:$user" "$ssh_dir"
|
||||
sudo chmod 700 "$ssh_dir"
|
||||
|
||||
# Generate Ed25519 key (more secure than RSA)
|
||||
sudo -u "$user" ssh-keygen -t ed25519 -f "$ssh_dir/id_ed25519" -N "" -C "NAS-$user-$(date +%Y%m%d)"
|
||||
|
||||
log_success "SSH keys generated. Public key: $ssh_dir/id_ed25519.pub"
|
||||
log_info "Add the public key to authorized_keys for passwordless login."
|
||||
}
|
||||
|
||||
# Main security configuration function
|
||||
configure_security() {
|
||||
log_info "=== Security Configuration ==="
|
||||
|
||||
secure_shared_memory
|
||||
install_fail2ban
|
||||
harden_ssh
|
||||
configure_mandatory_access_control
|
||||
install_auditd
|
||||
disable_unnecessary_services
|
||||
configure_security_updates
|
||||
generate_ssh_keys
|
||||
|
||||
log_success "Security configuration completed."
|
||||
}
|
||||
|
||||
@@ -1,38 +1,98 @@
|
||||
#!/bin/bash
|
||||
|
||||
# unattended-upgrades.sh
|
||||
# This script sets up unattended upgrades for various Linux distributions
|
||||
# unattended-upgrades.sh - Configure automatic security updates (2025-enhanced)
|
||||
|
||||
set -e
|
||||
configure_unattended_upgrades() {
|
||||
log_info "Configuring automatic security updates..."
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
# Preseed debconf to avoid interactive prompts and install non-interactively
|
||||
sudo debconf-set-selections <<DEBCONF
|
||||
unattended-upgrades unattended-upgrades/enable_auto_updates boolean true
|
||||
DEBCONF
|
||||
# Install non-interactively and avoid dpkg prompts by forcing noninteractive frontend
|
||||
# Use 'sudo env' to ensure environment vars are set for the root process
|
||||
handle_error sudo env DEBIAN_FRONTEND=noninteractive APT_LISTCHANGES_FRONTEND=none apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y unattended-upgrades apt-listchanges
|
||||
# Do not call dpkg-reconfigure interactively; we will write the config files directly
|
||||
|
||||
# Configure unattended-upgrades for security only
|
||||
sudo tee /etc/apt/apt.conf.d/50unattended-upgrades > /dev/null <<EOF
|
||||
Unattended-Upgrade::Allowed-Origins {
|
||||
"\${distro_id}:\${distro_codename}-security";
|
||||
"\${distro_id}ESMApps:\${distro_codename}-apps-security";
|
||||
"\${distro_id}ESM:\${distro_codename}-infra-security";
|
||||
};
|
||||
|
||||
DISTRO=$(lsb_release -is)
|
||||
Unattended-Upgrade::Package-Blacklist {
|
||||
};
|
||||
|
||||
case "$DISTRO" in
|
||||
Ubuntu|Debian)
|
||||
echo "Setting up unattended upgrades for $DISTRO..."
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y unattended-upgrades
|
||||
sudo dpkg-reconfigure --priority=low unattended-upgrades
|
||||
;;
|
||||
Fedora)
|
||||
echo "Setting up unattended upgrades for Fedora..."
|
||||
sudo dnf install -y dnf-automatic
|
||||
sudo systemctl enable --now dnf-automatic-install.timer
|
||||
;;
|
||||
"Arch Linux")
|
||||
echo "Setting up unattended upgrades for Arch Linux..."
|
||||
sudo pacman -Syu --noconfirm
|
||||
sudo systemctl enable --now paccache.timer
|
||||
;;
|
||||
openSUSE)
|
||||
echo "Setting up unattended upgrades for openSUSE..."
|
||||
sudo zypper install -y yast2-online-update-configuration
|
||||
sudo yast2 online_update_configuration
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported distribution: $DISTRO"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
|
||||
Unattended-Upgrade::MinimalSteps "true";
|
||||
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
||||
Unattended-Upgrade::Automatic-Reboot "false";
|
||||
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
|
||||
EOF
|
||||
|
||||
echo "Unattended upgrades setup complete."
|
||||
# Enable unattended-upgrades
|
||||
sudo tee /etc/apt/apt.conf.d/20auto-upgrades > /dev/null <<EOF
|
||||
APT::Periodic::Update-Package-Lists "1";
|
||||
APT::Periodic::Unattended-Upgrade "1";
|
||||
APT::Periodic::AutocleanInterval "7";
|
||||
EOF
|
||||
;;
|
||||
fedora)
|
||||
handle_error sudo dnf install -y dnf-automatic
|
||||
sudo systemctl enable --now dnf-automatic-install.timer
|
||||
|
||||
# Configure for security updates only
|
||||
sudo sed -i 's/upgrade_type = default/upgrade_type = security/' /etc/dnf/automatic.conf
|
||||
sudo sed -i 's/apply_updates = no/apply_updates = yes/' /etc/dnf/automatic.conf
|
||||
;;
|
||||
arch)
|
||||
log_info "Arch Linux: Automatic updates via pacman hooks recommended."
|
||||
# Create a systemd timer for security updates
|
||||
sudo tee /etc/systemd/system/pacman-security-update.service > /dev/null <<EOF
|
||||
[Unit]
|
||||
Description=Pacman Security Update
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/pacman -Syu --noconfirm
|
||||
EOF
|
||||
|
||||
sudo tee /etc/systemd/system/pacman-security-update.timer > /dev/null <<EOF
|
||||
[Unit]
|
||||
Description=Run security updates daily
|
||||
|
||||
[Timer]
|
||||
OnCalendar=daily
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
EOF
|
||||
|
||||
sudo systemctl enable pacman-security-update.timer
|
||||
;;
|
||||
opensuse)
|
||||
handle_error sudo zypper install -y yast2-online-update-configuration
|
||||
# Configure for automatic security updates
|
||||
sudo sed -i 's/AUTOMATICALLY_UPDATE_PATCHES="no"/AUTOMATICALLY_UPDATE_PATCHES="yes"/' /etc/sysconfig/automatic_online_update
|
||||
sudo systemctl enable --now automatic-online-update.timer
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported distribution: $DISTRO"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Automatic security updates configured."
|
||||
}
|
||||
|
||||
# Logging functions if not available
|
||||
if ! command -v log_info &>/dev/null; then
|
||||
log_info() { echo "[INFO] $1"; }
|
||||
log_success() { echo "[SUCCESS] $1"; }
|
||||
log_error() { echo "[ERROR] $1" >&2; }
|
||||
fi
|
||||
@@ -1,64 +1,97 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Vaultwarden installation and configuration script
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# lib/vaultwarden.sh
|
||||
#
|
||||
# Korrigierte Vaultwarden-Installationsbibliothek für das NAS-Setup-Skript.
|
||||
# Änderungen:
|
||||
# - Kein Top-Level-Aufruf von install_vaultwarden beim Sourcen (verhindert sofortiges exit).
|
||||
# - Fehler führen zu `return`-Codes statt `exit`, damit der Aufrufer (setup.sh) entscheiden kann.
|
||||
# - Prüft, ob Docker vorhanden ist; gibt passenden Rückgabewert bei Fehlen zurück.
|
||||
# - Vorsichtiger Umgang mit existierenden Containern/Verzeichnissen.
|
||||
#
|
||||
# Diese Datei ist dafür gedacht, mit `source` in setup.sh geladen zu werden.
|
||||
|
||||
install_vaultwarden() {
|
||||
# Erwartet: log_info, log_error, log_success Funktionen sind verfügbar (aus lib/logging.sh)
|
||||
# Erwartet: VAULTWARDEN_DATA_DIR gesetzt (aus config/defaults.sh)
|
||||
local container_name="vaultwarden"
|
||||
local image="vaultwarden/server:latest"
|
||||
local host_port="${VAULTWARDEN_PORT:-8080}"
|
||||
local data_dir="${VAULTWARDEN_DATA_DIR:-/opt/vaultwarden}"
|
||||
|
||||
log_info "Installing Vaultwarden..."
|
||||
|
||||
if [ -f /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
OS=$ID
|
||||
else
|
||||
echo "Unsupported OS"
|
||||
exit 1
|
||||
# Prüfen: Docker vorhanden?
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
log_error "Docker ist nicht installiert."
|
||||
log_error "Bitte Docker zuerst installieren oder im Setup erlauben, Docker zu installieren."
|
||||
return 1
|
||||
fi
|
||||
|
||||
case $OS in
|
||||
ubuntu|debian)
|
||||
sudo apt update
|
||||
sudo apt install -y docker.io docker-compose
|
||||
;;
|
||||
fedora)
|
||||
sudo dnf install -y docker docker-compose
|
||||
;;
|
||||
arch)
|
||||
sudo pacman -Syu --noconfirm docker docker-compose
|
||||
;;
|
||||
opensuse)
|
||||
sudo zypper install -y docker docker-compose
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported OS"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
# Sicherstellen, dass das Datenverzeichnis vorhanden ist
|
||||
if ! mkdir -p "${data_dir}" >/dev/null 2>&1; then
|
||||
log_error "Konnte Datenverzeichnis '${data_dir}' nicht anlegen."
|
||||
return 2
|
||||
fi
|
||||
|
||||
sudo systemctl start docker
|
||||
sudo systemctl enable docker
|
||||
# Prüfen, ob ein Container mit dem gewünschten Namen bereits existiert
|
||||
if docker ps -a --format '{{.Names}}' | grep -xq "${container_name}"; then
|
||||
log_info "Ein Container mit Namen '${container_name}' existiert bereits."
|
||||
# Wenn der Container gestoppt ist, starten wir ihn; wenn er läuft, nichts tun.
|
||||
if docker ps --format '{{.Names}}' | grep -xq "${container_name}"; then
|
||||
log_info "Container '${container_name}' läuft bereits. Überspringe Erstellung."
|
||||
log_success "Vaultwarden ist (vermutlich) bereits installiert und läuft."
|
||||
return 0
|
||||
else
|
||||
log_info "Starte vorhandenen Container '${container_name}'..."
|
||||
if docker start "${container_name}" >/dev/null 2>&1; then
|
||||
log_success "Container '${container_name}' erfolgreich gestartet."
|
||||
return 0
|
||||
else
|
||||
log_error "Fehler beim Starten des Containers '${container_name}'."
|
||||
return 3
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p ~/vaultwarden
|
||||
cd ~/vaultwarden
|
||||
# Pull the image first (optional, improves reliability)
|
||||
log_info "Lade Vaultwarden-Image '${image}' herunter..."
|
||||
if ! docker pull "${image}"; then
|
||||
log_error "Fehler beim Herunterladen des Images '${image}'."
|
||||
return 4
|
||||
fi
|
||||
|
||||
cat <<EOF > docker-compose.yml
|
||||
version: '3'
|
||||
services:
|
||||
vaultwarden:
|
||||
image: vaultwarden/server:latest
|
||||
container_name: vaultwarden
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./vw-data:/data
|
||||
ports:
|
||||
- 80:80
|
||||
EOF
|
||||
# Start the container (grundlegendes Beispiel)
|
||||
# Anpassungen möglich: Ports, Umgebungsvariablen (z.B. ADMIN_TOKEN), Volumes, Netzwerke.
|
||||
log_info "Erstelle und starte Container '${container_name}' (Port ${host_port})..."
|
||||
if docker run -d \
|
||||
--name "${container_name}" \
|
||||
--restart unless-stopped \
|
||||
-v "${data_dir}:/data" \
|
||||
-p "${host_port}:80" \
|
||||
"${image}" >/dev/null 2>&1; then
|
||||
|
||||
# Pull the Vaultwarden image
|
||||
handle_error sudo docker pull vaultwarden/server:latest
|
||||
|
||||
# Create the Vaultwarden container
|
||||
handle_error sudo docker run -d --name vaultwarden -v /vw-data/:/data/ -p 80:80 --restart always vaultwarden/server:latest
|
||||
|
||||
log_info "Vaultwarden installation completed."
|
||||
log_success "Vaultwarden-Container '${container_name}' erfolgreich erstellt und gestartet."
|
||||
log_info "Vaultwarden erreichbar auf Port ${host_port} (http)."
|
||||
return 0
|
||||
else
|
||||
log_error "Fehler beim Erstellen/Starten des Vaultwarden-Containers."
|
||||
return 5
|
||||
fi
|
||||
}
|
||||
|
||||
install_vaultwarden
|
||||
# Optional: Helfer, der prüft ob Vaultwarden bereits installiert ist (Exit-Code 0 = installiert)
|
||||
is_vaultwarden_installed() {
|
||||
if command -v docker >/dev/null 2>&1 && docker ps -a --format '{{.Names}}' | grep -xq '^vaultwarden$'; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Nur ausführen, wenn diese Datei direkt ausgeführt wird (nicht beim `source` in setup.sh).
|
||||
# Das erlaubt unabhängiges Testen, ohne dass Sourcing das Haupt-Skript beendet.
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
# Falls direkt ausgeführt: versuchen wir die Funktion und geben das Ergebnis als Exit-Code zurück.
|
||||
install_vaultwarden "$@"
|
||||
exit $?
|
||||
fi
|
||||
122
lib/webmin.sh
Normal file
122
lib/webmin.sh
Normal file
@@ -0,0 +1,122 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Webmin installation and configuration
|
||||
|
||||
install_webmin() {
|
||||
if [[ "${INSTALL_WEBMIN:-false}" != "true" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Installing Webmin web interface..."
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
# Download and run Webmin setup script
|
||||
handle_error curl -o setup-repos.sh https://raw.githubusercontent.com/webmin/webmin/master/setup-repos.sh
|
||||
handle_error sudo bash setup-repos.sh
|
||||
|
||||
# Install Webmin
|
||||
handle_error sudo apt update
|
||||
handle_error sudo apt install -y webmin
|
||||
|
||||
# Clean up setup script
|
||||
rm -f setup-repos.sh
|
||||
;;
|
||||
fedora)
|
||||
# Add Webmin repository
|
||||
handle_error sudo curl -o /etc/yum.repos.d/webmin.repo https://raw.githubusercontent.com/webmin/webmin/master/webmin.repo
|
||||
handle_error sudo dnf install -y webmin
|
||||
;;
|
||||
opensuse)
|
||||
# Webmin is not available in official openSUSE Leap repositories
|
||||
# For openSUSE, Webmin needs to be installed manually or from third-party repos
|
||||
log_warning "Webmin is not available in official openSUSE Leap repositories"
|
||||
log_info "To install Webmin on openSUSE manually:"
|
||||
log_info "1. Download from https://www.webmin.com/download.html"
|
||||
log_info "2. Follow the manual installation instructions"
|
||||
log_info "3. Webmin will be available at https://your-server:10000"
|
||||
return 1
|
||||
;;
|
||||
arch)
|
||||
# Webmin is available in AUR
|
||||
log_warning "Webmin installation on Arch Linux requires manual AUR installation"
|
||||
log_info "Please install Webmin manually from AUR: yay -S webmin"
|
||||
log_info "Then run: sudo systemctl enable webmin && sudo systemctl start webmin"
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
log_error "Webmin installation not supported for $DISTRO"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Enable and start Webmin service
|
||||
handle_error sudo systemctl enable webmin
|
||||
handle_error sudo systemctl start webmin
|
||||
|
||||
# Configure firewall for Webmin (port 10000)
|
||||
configure_webmin_firewall
|
||||
|
||||
# Get IP address for access information
|
||||
local ip_address=$(hostname -I | awk '{print $1}')
|
||||
|
||||
log_success "Webmin installed and configured"
|
||||
log_info "Webmin is available at: https://${ip_address}:10000"
|
||||
log_info "Default login: root / your root password"
|
||||
log_warning "Important: Change the default password after first login!"
|
||||
log_info "Note: Webmin uses self-signed SSL certificate - accept the security warning"
|
||||
|
||||
# Add to rollback
|
||||
add_rollback_action "sudo systemctl disable webmin && sudo systemctl stop webmin && sudo apt remove -y webmin"
|
||||
}
|
||||
|
||||
# Configure firewall for Webmin access
|
||||
configure_webmin_firewall() {
|
||||
log_info "Configuring firewall for Webmin access..."
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian|arch)
|
||||
# UFW firewall
|
||||
if command -v ufw &> /dev/null; then
|
||||
handle_error sudo ufw allow 10000/tcp
|
||||
log_info "UFW rule added: allow port 10000/tcp for Webmin"
|
||||
fi
|
||||
;;
|
||||
fedora|opensuse)
|
||||
# Firewalld
|
||||
if command -v firewall-cmd &> /dev/null; then
|
||||
handle_error sudo firewall-cmd --permanent --add-port=10000/tcp
|
||||
handle_error sudo firewall-cmd --reload
|
||||
log_info "Firewalld rule added: allow port 10000/tcp for Webmin"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Webmin configuration optimization
|
||||
configure_webmin() {
|
||||
if [[ "${INSTALL_WEBMIN:-false}" != "true" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Configuring Webmin optimizations..."
|
||||
|
||||
# Webmin configuration file
|
||||
local webmin_config="/etc/webmin/miniserv.conf"
|
||||
|
||||
if [[ -f "$webmin_config" ]]; then
|
||||
# Increase session timeout
|
||||
sudo sed -i 's/^session_timeout=.*/session_timeout=3600/' "$webmin_config"
|
||||
|
||||
# Configure SSL settings
|
||||
sudo sed -i 's/^ssl=.*/ssl=1/' "$webmin_config"
|
||||
sudo sed -i 's/^ssl_redirect=.*/ssl_redirect=1/' "$webmin_config"
|
||||
|
||||
# Restart Webmin to apply changes
|
||||
handle_error sudo systemctl restart webmin
|
||||
|
||||
log_success "Webmin configuration optimized"
|
||||
else
|
||||
log_warning "Webmin configuration file not found - skipping optimization"
|
||||
fi
|
||||
}
|
||||
101
scripts/repair_docker.sh
Normal file
101
scripts/repair_docker.sh
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Repair helper for Docker daemon config and service
|
||||
# - Validates /etc/docker/daemon.json (using jq or python3)
|
||||
# - Backs up invalid config and writes a minimal valid config
|
||||
# - Restarts docker and collects logs
|
||||
# - Attempts to run configure_docker_daemon from the repo if available
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
LOGFILE="/tmp/repair_docker_$(date +%s).log"
|
||||
|
||||
echo "Repair started at $(date)" > "$LOGFILE"
|
||||
|
||||
# Load repo helpers if present
|
||||
if [[ -f "$SCRIPT_DIR/config/defaults.sh" ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source "$SCRIPT_DIR/config/defaults.sh" || true
|
||||
fi
|
||||
if [[ -f "$SCRIPT_DIR/lib/common.sh" ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source "$SCRIPT_DIR/lib/common.sh" || true
|
||||
fi
|
||||
if [[ -f "$SCRIPT_DIR/lib/docker.sh" ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source "$SCRIPT_DIR/lib/docker.sh" || true
|
||||
fi
|
||||
|
||||
validate_json() {
|
||||
local file="$1"
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
jq empty "$file" >/dev/null 2>&1
|
||||
return $?
|
||||
elif command -v python3 >/dev/null 2>&1; then
|
||||
python3 -m json.tool "$file" >/dev/null 2>&1
|
||||
return $?
|
||||
else
|
||||
# conservative: try to detect a trailing EOF or obvious truncation
|
||||
if [[ -s "$file" ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
echo "Using repo at: $SCRIPT_DIR" >> "$LOGFILE"
|
||||
|
||||
if [[ -f /etc/docker/daemon.json ]]; then
|
||||
echo "/etc/docker/daemon.json exists - validating..." | tee -a "$LOGFILE"
|
||||
if validate_json /etc/docker/daemon.json; then
|
||||
echo "daemon.json is valid" | tee -a "$LOGFILE"
|
||||
else
|
||||
echo "daemon.json is INVALID - backing up and replacing with minimal config" | tee -a "$LOGFILE"
|
||||
sudo mkdir -p /tmp/docker-repair-backups
|
||||
sudo mv /etc/docker/daemon.json "/tmp/docker-repair-backups/daemon.json.broken.$(date +%s)"
|
||||
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
|
||||
{
|
||||
"storage-driver": "overlay2"
|
||||
}
|
||||
EOF
|
||||
echo "Wrote minimal /etc/docker/daemon.json" | tee -a "$LOGFILE"
|
||||
fi
|
||||
else
|
||||
echo "/etc/docker/daemon.json does not exist - creating minimal config" | tee -a "$LOGFILE"
|
||||
sudo mkdir -p /etc/docker
|
||||
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
|
||||
{
|
||||
"storage-driver": "overlay2"
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo "Reloading systemd daemon and restarting docker" | tee -a "$LOGFILE"
|
||||
sudo systemctl daemon-reload || true
|
||||
if sudo systemctl restart docker; then
|
||||
echo "Docker restarted successfully" | tee -a "$LOGFILE"
|
||||
sudo journalctl -u docker --no-pager -n 200 >> "$LOGFILE" 2>&1 || true
|
||||
else
|
||||
echo "Docker failed to restart - collecting logs" | tee -a "$LOGFILE"
|
||||
sudo journalctl -u docker --no-pager -n 500 >> "$LOGFILE" 2>&1 || true
|
||||
|
||||
# Try to run configure_docker_daemon from this repo if available
|
||||
if declare -F configure_docker_daemon >/dev/null 2>&1; then
|
||||
echo "Attempting to run configure_docker_daemon() from repo" | tee -a "$LOGFILE"
|
||||
if configure_docker_daemon >> "$LOGFILE" 2>&1; then
|
||||
echo "configure_docker_daemon executed - attempting docker restart" | tee -a "$LOGFILE"
|
||||
sudo systemctl restart docker >> "$LOGFILE" 2>&1 || true
|
||||
sudo journalctl -u docker --no-pager -n 200 >> "$LOGFILE" 2>&1 || true
|
||||
else
|
||||
echo "configure_docker_daemon failed" | tee -a "$LOGFILE"
|
||||
fi
|
||||
else
|
||||
echo "configure_docker_daemon function not available in sourced repo files" | tee -a "$LOGFILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Repair finished at $(date)" | tee -a "$LOGFILE"
|
||||
echo "Logfile: $LOGFILE"
|
||||
|
||||
exit 0
|
||||
592
setup.sh
592
setup.sh
@@ -1,14 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
# NAS Setup Script - Version 2.0.0
|
||||
# NAS Setup Script - Version 2.1.1
|
||||
#
|
||||
# This script automates the setup of a NAS system with various services.
|
||||
# It is designed to run on multiple Linux distributions, including:
|
||||
# - Ubuntu 20.04+
|
||||
# - Debian 11+
|
||||
# - Fedora 35+
|
||||
# - Ubuntu 24.04+
|
||||
# - Debian 12+
|
||||
# - Fedora 41+
|
||||
# - Arch Linux
|
||||
# - openSUSE Leap 15.4+
|
||||
# - openSUSE Leap 15.6+
|
||||
#
|
||||
# Disclaimer:
|
||||
# This script is provided "as is", without warranty of any kind, express or implied,
|
||||
@@ -34,6 +34,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/config/defaults.sh"
|
||||
source "${SCRIPT_DIR}/lib/logging.sh"
|
||||
source "${SCRIPT_DIR}/lib/common.sh"
|
||||
source "${SCRIPT_DIR}/lib/detection.sh"
|
||||
source "${SCRIPT_DIR}/lib/network.sh"
|
||||
source "${SCRIPT_DIR}/lib/docker.sh"
|
||||
source "${SCRIPT_DIR}/lib/security.sh"
|
||||
@@ -45,6 +46,7 @@ source "${SCRIPT_DIR}/lib/unattended-upgrades.sh"
|
||||
source "${SCRIPT_DIR}/lib/vaultwarden.sh"
|
||||
source "${SCRIPT_DIR}/lib/jellyfin.sh"
|
||||
source "${SCRIPT_DIR}/lib/portainer.sh"
|
||||
source "${SCRIPT_DIR}/lib/webmin.sh"
|
||||
source "${SCRIPT_DIR}/lib/performance.sh"
|
||||
|
||||
# Initialize logging
|
||||
@@ -56,16 +58,35 @@ exec > >(tee -a "${LOG_FILE}") 2>&1
|
||||
|
||||
# Enhanced error handling with rollback
|
||||
handle_error() {
|
||||
# Dual-mode: if called with a non-numeric first argument, treat as wrapper
|
||||
# e.g. handle_error sudo cp ... -> execute the command and handle failures
|
||||
if [[ $# -ge 1 && ! "$1" =~ ^[0-9]+$ ]]; then
|
||||
"$@"
|
||||
local _rc=$?
|
||||
if [[ $_rc -ne 0 ]]; then
|
||||
local _line_number=${BASH_LINENO[0]:-0}
|
||||
local _command="$*"
|
||||
log_error "Script failed at line ${_line_number}: ${_command} (exit code: ${_rc})"
|
||||
if ask_yes_no "An error occurred. Would you like to rollback changes?" "y"; then
|
||||
execute_rollback
|
||||
fi
|
||||
cleanup
|
||||
exit $_rc
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Trap handler mode: handle_error <line> "<command>"
|
||||
local exit_code=$?
|
||||
local line_number=$1
|
||||
local command="$2"
|
||||
|
||||
|
||||
log_error "Script failed at line ${line_number}: ${command} (exit code: ${exit_code})"
|
||||
|
||||
|
||||
if ask_yes_no "An error occurred. Would you like to rollback changes?" "y"; then
|
||||
execute_rollback
|
||||
fi
|
||||
|
||||
|
||||
cleanup
|
||||
exit $exit_code
|
||||
}
|
||||
@@ -82,40 +103,147 @@ cleanup_on_exit() {
|
||||
|
||||
trap cleanup_on_exit SIGINT SIGTERM
|
||||
|
||||
# Detect Linux distribution with version check
|
||||
# Detect Linux distribution with comprehensive fallback methods
|
||||
detect_distro() {
|
||||
local detected_distro=""
|
||||
local detected_version=""
|
||||
local detected_codename=""
|
||||
local detection_method=""
|
||||
|
||||
log_debug "Starting distribution detection..."
|
||||
|
||||
# Method 1: /etc/os-release (primary method for modern systems)
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
source /etc/os-release
|
||||
DISTRO=$ID
|
||||
DISTRO_VERSION=$VERSION_ID
|
||||
DISTRO_CODENAME=${VERSION_CODENAME:-""}
|
||||
|
||||
log_info "Detected distribution: $PRETTY_NAME"
|
||||
|
||||
# Validate supported distribution
|
||||
if [[ ! " ${SUPPORTED_DISTROS[*]} " =~ " ${DISTRO} " ]]; then
|
||||
log_error "Unsupported Linux distribution: $DISTRO"
|
||||
log_info "Supported distributions: ${SUPPORTED_DISTROS[*]}"
|
||||
exit 1
|
||||
source /etc/os-release 2>/dev/null || true
|
||||
detected_distro=${ID,,} # Convert to lowercase
|
||||
detected_version=$VERSION_ID
|
||||
detected_codename=${VERSION_CODENAME:-${UBUNTU_CODENAME:-""}}
|
||||
detected_pretty_name=$PRETTY_NAME
|
||||
detection_method="/etc/os-release"
|
||||
log_debug "Detected via /etc/os-release: $PRETTY_NAME"
|
||||
fi
|
||||
|
||||
# Method 2: /etc/redhat-release (fallback for RHEL/CentOS/Fedora)
|
||||
if [[ -z "$detected_distro" ]] && [[ -f /etc/redhat-release ]]; then
|
||||
local redhat_info=$(cat /etc/redhat-release)
|
||||
if [[ $redhat_info =~ ^(CentOS|Red Hat Enterprise|Fedora) ]]; then
|
||||
detected_distro="fedora"
|
||||
detected_version=$(echo "$redhat_info" | grep -oP '\d+\.\d+' | head -1)
|
||||
detection_method="/etc/redhat-release"
|
||||
log_debug "Detected via /etc/redhat-release: $redhat_info"
|
||||
fi
|
||||
|
||||
# Check minimum versions
|
||||
case $DISTRO in
|
||||
ubuntu)
|
||||
if [[ $(echo "$DISTRO_VERSION >= 20.04" | bc -l) -eq 0 ]]; then
|
||||
log_warning "Ubuntu version $DISTRO_VERSION is not officially supported. Minimum: 20.04"
|
||||
fi
|
||||
;;
|
||||
debian)
|
||||
if [[ ${DISTRO_VERSION%%.*} -lt 11 ]]; then
|
||||
log_warning "Debian version $DISTRO_VERSION is not officially supported. Minimum: 11"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
else
|
||||
log_error "Cannot detect Linux distribution. /etc/os-release not found."
|
||||
fi
|
||||
|
||||
# Method 3: /etc/debian_version (fallback for Debian/Ubuntu)
|
||||
if [[ -z "$detected_distro" ]] && [[ -f /etc/debian_version ]]; then
|
||||
local debian_version=$(cat /etc/debian_version)
|
||||
if [[ -f /etc/lsb-release ]]; then
|
||||
source /etc/lsb-release 2>/dev/null || true
|
||||
detected_distro=${DISTRIB_ID,,}
|
||||
detected_version=$DISTRIB_RELEASE
|
||||
detected_codename=${DISTRIB_CODENAME:-""}
|
||||
detection_method="/etc/lsb-release"
|
||||
else
|
||||
# Pure Debian system
|
||||
detected_distro="debian"
|
||||
detected_version=$debian_version
|
||||
detection_method="/etc/debian_version"
|
||||
fi
|
||||
log_debug "Detected via Debian method: $detected_distro $detected_version"
|
||||
fi
|
||||
|
||||
# Method 4: lsb_release command (fallback)
|
||||
if [[ -z "$detected_distro" ]] && command -v lsb_release >/dev/null 2>&1; then
|
||||
detected_distro=$(lsb_release -si 2>/dev/null | tr '[:upper:]' '[:lower:]')
|
||||
detected_version=$(lsb_release -sr 2>/dev/null)
|
||||
detected_codename=$(lsb_release -sc 2>/dev/null)
|
||||
detection_method="lsb_release command"
|
||||
log_debug "Detected via lsb_release command: $detected_distro $detected_version"
|
||||
fi
|
||||
|
||||
# Method 5: uname and manual detection (last resort)
|
||||
if [[ -z "$detected_distro" ]]; then
|
||||
if [[ -f /etc/arch-release ]]; then
|
||||
detected_distro="arch"
|
||||
detected_version="rolling"
|
||||
detection_method="/etc/arch-release"
|
||||
elif [[ -f /etc/gentoo-release ]]; then
|
||||
detected_distro="gentoo"
|
||||
detected_version=$(cat /etc/gentoo-release | grep -oP '\d+\.\d+' | head -1)
|
||||
detection_method="/etc/gentoo-release"
|
||||
elif uname -a | grep -qi "opensuse"; then
|
||||
detected_distro="opensuse"
|
||||
detected_version="unknown"
|
||||
detection_method="uname opensuse"
|
||||
fi
|
||||
log_debug "Detected via fallback method: $detected_distro"
|
||||
fi
|
||||
|
||||
# Validate detection
|
||||
if [[ -z "$detected_distro" ]]; then
|
||||
log_error "Failed to detect Linux distribution using all available methods"
|
||||
log_error "Please check your system and ensure it's a supported Linux distribution"
|
||||
log_error "Supported: ${SUPPORTED_DISTROS[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Normalize distribution names
|
||||
case $detected_distro in
|
||||
ubuntu|debian|fedora|arch|opensuse|opensuse-leap)
|
||||
if [[ "$detected_distro" == "opensuse-leap" ]]; then
|
||||
DISTRO="opensuse"
|
||||
else
|
||||
DISTRO=$detected_distro
|
||||
fi
|
||||
;;
|
||||
"red hat enterprise linux server"|"rhel")
|
||||
DISTRO="fedora" # Treat RHEL as Fedora for package management
|
||||
;;
|
||||
"centos linux"|"centos")
|
||||
DISTRO="fedora" # CentOS uses same package manager as Fedora
|
||||
;;
|
||||
*)
|
||||
# Check if it's a known variant
|
||||
if [[ " ${SUPPORTED_DISTROS[*]} " =~ " ${detected_distro} " ]]; then
|
||||
DISTRO=$detected_distro
|
||||
else
|
||||
log_error "Detected distribution '$detected_distro' is not in supported list"
|
||||
log_error "Supported distributions: ${SUPPORTED_DISTROS[*]}"
|
||||
log_error "Detection method: $detection_method"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# Parse and normalize version
|
||||
DISTRO_VERSION=$(normalize_version "$detected_version")
|
||||
DISTRO_CODENAME=$detected_codename
|
||||
DISTRO_NAME=${detected_pretty_name:-$DISTRO}
|
||||
|
||||
log_info "Distribution detected: $DISTRO $DISTRO_VERSION ($detection_method)"
|
||||
if [[ -n "$DISTRO_CODENAME" ]]; then
|
||||
log_debug "Codename: $DISTRO_CODENAME"
|
||||
fi
|
||||
|
||||
# Validate supported distribution
|
||||
if [[ ! " ${SUPPORTED_DISTROS[*]} " =~ " ${DISTRO} " ]]; then
|
||||
log_error "Unsupported Linux distribution: $DISTRO"
|
||||
log_info "Supported distributions: ${SUPPORTED_DISTROS[*]}"
|
||||
log_info "Detection method: $detection_method"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check minimum versions with improved parsing
|
||||
validate_minimum_version "$DISTRO" "$DISTRO_VERSION"
|
||||
|
||||
# Check for container environments
|
||||
detect_container_environment
|
||||
|
||||
# Cache the results for performance
|
||||
export DISTRO DETECTED_DISTRO=$DISTRO
|
||||
export DISTRO_VERSION DETECTED_VERSION=$DISTRO_VERSION
|
||||
export DISTRO_CODENAME DETECTED_CODENAME=$DISTRO_CODENAME
|
||||
export DISTRO_NAME
|
||||
}
|
||||
|
||||
# System requirements check
|
||||
@@ -170,13 +298,18 @@ load_or_create_config() {
|
||||
if load_config; then
|
||||
log_info "Configuration loaded from ${CONFIG_FILE}"
|
||||
if ! validate_config; then
|
||||
log_error "Configuration validation failed"
|
||||
exit 1
|
||||
log_warning "Configuration validation failed - creating new configuration"
|
||||
create_interactive_config
|
||||
load_config # Reload the new configuration
|
||||
fi
|
||||
else
|
||||
log_info "Creating new configuration..."
|
||||
create_interactive_config
|
||||
load_config # Load the new configuration
|
||||
fi
|
||||
|
||||
# Export configuration variables for use in subshells
|
||||
export ADMIN_USER SSH_PORT CONFIGURE_STATIC_IP INSTALL_DOCKER INSTALL_NFS INSTALL_NETDATA INSTALL_VAULTWARDEN INSTALL_JELLYFIN INSTALL_PORTAINER INSTALL_WEBMIN ENABLE_AUTO_UPDATES
|
||||
}
|
||||
|
||||
create_interactive_config() {
|
||||
@@ -188,8 +321,20 @@ create_interactive_config() {
|
||||
save_config "SSH_PORT" "$ssh_port"
|
||||
|
||||
# User configuration
|
||||
local username=$(ask_input "Admin username" "$NEW_USER" "validate_username")
|
||||
local current_user
|
||||
if [[ -n "${SUDO_USER:-}" ]]; then
|
||||
current_user="$SUDO_USER"
|
||||
log_info "Using current sudo user: $current_user"
|
||||
else
|
||||
current_user="$USER"
|
||||
log_info "Using current user: $current_user"
|
||||
fi
|
||||
|
||||
# Pre-fill with current user, but allow override
|
||||
local username=$(ask_input "Admin username" "$current_user" "validate_username")
|
||||
save_config "ADMIN_USER" "$username"
|
||||
# Ensure the configured admin user exists (offer interactive creation)
|
||||
ensure_user_exists_interactive "$username" || log_warning "Admin user '$username' not created; some features may require it."
|
||||
|
||||
# Network configuration
|
||||
if ask_yes_no "Configure static IP?" "n"; then
|
||||
@@ -199,12 +344,33 @@ create_interactive_config() {
|
||||
fi
|
||||
|
||||
# Service selection
|
||||
save_config "INSTALL_DOCKER" "$(ask_yes_no "Install Docker?" "y" && echo "true" || echo "false")"
|
||||
local install_docker=$(ask_yes_no "Install Docker?" "y" && echo "true" || echo "false")
|
||||
save_config "INSTALL_DOCKER" "$install_docker"
|
||||
save_config "INSTALL_NFS" "$(ask_yes_no "Install NFS?" "n" && echo "true" || echo "false")"
|
||||
save_config "INSTALL_NETDATA" "$(ask_yes_no "Install Netdata monitoring?" "y" && echo "true" || echo "false")"
|
||||
save_config "INSTALL_VAULTWARDEN" "$(ask_yes_no "Install Vaultwarden password manager?" "n" && echo "true" || echo "false")"
|
||||
save_config "INSTALL_JELLYFIN" "$(ask_yes_no "Install Jellyfin media server?" "n" && echo "true" || echo "false")"
|
||||
save_config "INSTALL_PORTAINER" "$(ask_yes_no "Install Portainer Docker management?" "n" && echo "true" || echo "false")"
|
||||
|
||||
# Docker-dependent services
|
||||
if [[ "$install_docker" == "true" ]]; then
|
||||
save_config "INSTALL_VAULTWARDEN" "$(ask_yes_no "Install Vaultwarden password manager?" "n" && echo "true" || echo "false")"
|
||||
save_config "INSTALL_JELLYFIN" "$(ask_yes_no "Install Jellyfin media server?" "n" && echo "true" || echo "false")"
|
||||
save_config "INSTALL_PORTAINER" "$(ask_yes_no "Install Portainer Docker management?" "n" && echo "true" || echo "false")"
|
||||
else
|
||||
log_warning "Docker not selected - skipping Docker-dependent services (Vaultwarden, Jellyfin, Portainer)"
|
||||
save_config "INSTALL_VAULTWARDEN" "false"
|
||||
save_config "INSTALL_JELLYFIN" "false"
|
||||
save_config "INSTALL_PORTAINER" "false"
|
||||
fi
|
||||
|
||||
# Automatic updates (optional)
|
||||
save_config "ENABLE_AUTO_UPDATES" "$(ask_yes_no "Enable automatic security updates (unattended-upgrades)?" "n" && echo "true" || echo "false")"
|
||||
|
||||
# Webmin (not available on openSUSE)
|
||||
if [[ "$DISTRO" == "opensuse" ]]; then
|
||||
log_info "Webmin is not available for openSUSE Leap - skipping"
|
||||
save_config "INSTALL_WEBMIN" "false"
|
||||
else
|
||||
save_config "INSTALL_WEBMIN" "$(ask_yes_no "Install Webmin web interface?" "n" && echo "true" || echo "false")"
|
||||
fi
|
||||
|
||||
log_success "Configuration created and saved to ${CONFIG_FILE}"
|
||||
}
|
||||
@@ -227,8 +393,9 @@ update_system() {
|
||||
sudo pacman -Syu --noconfirm --quiet
|
||||
;;
|
||||
opensuse)
|
||||
sudo zypper refresh -q
|
||||
sudo zypper update -y -q
|
||||
sudo zypper refresh
|
||||
show_progress 5 10 "System Update"
|
||||
sudo zypper update -y
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -238,93 +405,190 @@ update_system() {
|
||||
|
||||
# Main installation orchestrator
|
||||
run_installation() {
|
||||
local total_steps=12
|
||||
local total_steps=13
|
||||
local current_step=0
|
||||
|
||||
log_info "Starting NAS installation process..."
|
||||
|
||||
# Core system setup
|
||||
((current_step++)); show_progress $current_step $total_steps "Installing dependencies"
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to install dependencies (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing dependencies"
|
||||
install_dependencies
|
||||
|
||||
((current_step++)); show_progress $current_step $total_steps "Configuring network"
|
||||
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to configure network (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Configuring network"
|
||||
if [[ "${CONFIGURE_STATIC_IP:-false}" == "true" ]]; then
|
||||
configure_network
|
||||
fi
|
||||
|
||||
((current_step++)); show_progress $current_step $total_steps "Configuring SSH"
|
||||
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to configure SSH (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Configuring SSH"
|
||||
configure_ssh
|
||||
|
||||
((current_step++)); show_progress $current_step $total_steps "Setting up Samba"
|
||||
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to setup Samba (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Setting up Samba"
|
||||
setup_samba
|
||||
|
||||
((current_step++)); show_progress $current_step $total_steps "Configuring firewall"
|
||||
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to configure firewall (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Configuring firewall"
|
||||
configure_firewall
|
||||
|
||||
# Security setup
|
||||
((current_step++)); show_progress $current_step $total_steps "Implementing security measures"
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to implement security measures (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Implementing security measures"
|
||||
secure_shared_memory
|
||||
install_fail2ban
|
||||
configure_automatic_updates
|
||||
# Configure automatic updates only if user opted in
|
||||
if [[ "${ENABLE_AUTO_UPDATES:-false}" == "true" ]]; then
|
||||
configure_automatic_updates
|
||||
else
|
||||
log_info "Automatic security updates are disabled by configuration"
|
||||
fi
|
||||
|
||||
# Optional services
|
||||
if [[ "${INSTALL_DOCKER:-false}" == "true" ]]; then
|
||||
((current_step++)); show_progress $current_step $total_steps "Installing Docker"
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to install Docker (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Docker"
|
||||
install_docker
|
||||
else
|
||||
((current_step++))
|
||||
current_step=$((current_step + 1))
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_NFS:-false}" == "true" ]]; then
|
||||
((current_step++)); show_progress $current_step $total_steps "Installing NFS"
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to install NFS (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing NFS"
|
||||
install_nfs
|
||||
else
|
||||
((current_step++))
|
||||
current_step=$((current_step + 1))
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_NETDATA:-false}" == "true" ]]; then
|
||||
((current_step++)); show_progress $current_step $total_steps "Installing Netdata"
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to install Netdata (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Netdata"
|
||||
install_netdata
|
||||
else
|
||||
((current_step++))
|
||||
current_step=$((current_step + 1))
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_VAULTWARDEN:-false}" == "true" ]]; then
|
||||
((current_step++)); show_progress $current_step $total_steps "Installing Vaultwarden"
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to install Vaultwarden (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Vaultwarden"
|
||||
install_vaultwarden
|
||||
else
|
||||
((current_step++))
|
||||
current_step=$((current_step + 1))
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_JELLYFIN:-false}" == "true" ]]; then
|
||||
((current_step++)); show_progress $current_step $total_steps "Installing Jellyfin"
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to install Jellyfin (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Jellyfin"
|
||||
install_jellyfin
|
||||
else
|
||||
((current_step++))
|
||||
current_step=$((current_step + 1))
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_PORTAINER:-false}" == "true" ]]; then
|
||||
((current_step++)); show_progress $current_step $total_steps "Installing Portainer"
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to install Portainer (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Portainer"
|
||||
install_portainer
|
||||
else
|
||||
((current_step++))
|
||||
current_step=$((current_step + 1))
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_WEBMIN:-false}" == "true" ]]; then
|
||||
current_step=$((current_step + 1)); log_debug "run_installation: about to install Webmin (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Webmin"
|
||||
install_webmin
|
||||
configure_webmin
|
||||
else
|
||||
current_step=$((current_step + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
# Restart all installed services to ensure they're active
|
||||
restart_all_services() {
|
||||
log_info "Restarting all installed services to ensure they're active..."
|
||||
|
||||
local services_to_restart=()
|
||||
|
||||
# Always restart SSH and Fail2ban if configured
|
||||
if [[ "${CONFIGURE_SSH:-true}" == "true" ]]; then
|
||||
services_to_restart+=("ssh" "sshd" "fail2ban")
|
||||
fi
|
||||
|
||||
# Add Samba services based on distribution
|
||||
if [[ "${INSTALL_SAMBA:-true}" == "true" ]]; then
|
||||
case $DISTRO in
|
||||
opensuse)
|
||||
services_to_restart+=("smb" "nmb")
|
||||
;;
|
||||
*)
|
||||
services_to_restart+=("smbd" "nmbd")
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Add other services if installed
|
||||
if [[ "${INSTALL_DOCKER:-false}" == "true" ]]; then
|
||||
services_to_restart+=("docker")
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_NETDATA:-false}" == "true" ]]; then
|
||||
services_to_restart+=("netdata")
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_NFS:-false}" == "true" ]]; then
|
||||
case $DISTRO in
|
||||
opensuse)
|
||||
services_to_restart+=("nfs-server")
|
||||
;;
|
||||
*)
|
||||
services_to_restart+=("nfs-kernel-server")
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Restart each service if it exists and is enabled
|
||||
for service in "${services_to_restart[@]}"; do
|
||||
if systemctl list-unit-files --type=service | grep -q "^${service}.service"; then
|
||||
if systemctl is-enabled "$service" &>/dev/null 2>&1; then
|
||||
log_info "Restarting service: $service"
|
||||
if sudo systemctl restart "$service"; then
|
||||
log_success "Service $service restarted successfully"
|
||||
else
|
||||
log_warning "Failed to restart service: $service"
|
||||
fi
|
||||
else
|
||||
log_debug "Service $service is not enabled, skipping restart"
|
||||
fi
|
||||
else
|
||||
log_debug "Service $service does not exist, skipping"
|
||||
fi
|
||||
done
|
||||
|
||||
# Special handling for SSH - use our robust restart function
|
||||
if [[ "${CONFIGURE_SSH:-true}" == "true" ]]; then
|
||||
log_info "Ensuring SSH service is properly restarted..."
|
||||
restart_ssh_service
|
||||
fi
|
||||
|
||||
log_success "Service restart process completed"
|
||||
}
|
||||
|
||||
# Installation summary
|
||||
show_installation_summary() {
|
||||
local ip_address
|
||||
ip_address=$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | head -1 | awk '{print $2}' | cut -d/ -f1)
|
||||
local user_home
|
||||
if [[ -n "${SUDO_USER:-}" ]]; then
|
||||
user_home=$(eval echo "~${SUDO_USER}")
|
||||
else
|
||||
user_home="$HOME"
|
||||
fi
|
||||
local summary_file="${user_home}/nas_services.txt"
|
||||
|
||||
echo
|
||||
log_success "=== NAS Setup Completed Successfully ==="
|
||||
echo
|
||||
log_info "Installation Summary:"
|
||||
echo " ✓ System updated and secured"
|
||||
echo " ✓ User '${ADMIN_USER:-$NEW_USER}' created with sudo access"
|
||||
echo " ✓ User '${ADMIN_USER:-$USER}' created with sudo access"
|
||||
echo " ✓ SSH configured on port ${SSH_PORT:-$DEFAULT_SSH_PORT}"
|
||||
echo " ✓ Samba file sharing configured"
|
||||
echo " ✓ Firewall configured and enabled"
|
||||
echo " ✓ Fail2ban installed and configured"
|
||||
echo " ✓ Automatic updates enabled"
|
||||
|
||||
if [[ "${ENABLE_AUTO_UPDATES:-false}" == "true" ]]; then
|
||||
echo " ✓ Automatic updates enabled"
|
||||
else
|
||||
echo " - Automatic updates not enabled (optional)"
|
||||
fi
|
||||
|
||||
# Service summary
|
||||
if [[ "${INSTALL_DOCKER:-false}" == "true" ]]; then
|
||||
echo " ✓ Docker installed and configured"
|
||||
@@ -333,27 +597,187 @@ show_installation_summary() {
|
||||
echo " ✓ NFS server installed"
|
||||
fi
|
||||
if [[ "${INSTALL_NETDATA:-false}" == "true" ]]; then
|
||||
echo " ✓ Netdata monitoring: http://$(hostname -I | awk '{print $1}'):${NETDATA_PORT}"
|
||||
echo " ✓ Netdata monitoring: http://${ip_address}:${NETDATA_PORT}"
|
||||
fi
|
||||
if [[ "${INSTALL_JELLYFIN:-false}" == "true" ]]; then
|
||||
echo " ✓ Jellyfin media server: http://$(hostname -I | awk '{print $1}'):8096"
|
||||
echo " ✓ Jellyfin media server: http://${ip_address}:8096"
|
||||
fi
|
||||
if [[ "${INSTALL_PORTAINER:-false}" == "true" ]]; then
|
||||
echo " ✓ Portainer Docker management: http://$(hostname -I | awk '{print $1}'):9000"
|
||||
echo " ✓ Portainer Docker management: http://${ip_address}:9000"
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_WEBMIN:-false}" == "true" ]]; then
|
||||
echo " ✓ Webmin web interface: https://${ip_address}:10000"
|
||||
fi
|
||||
|
||||
# Create services summary file
|
||||
log_info "Creating services summary file: ${summary_file}"
|
||||
cat > "${summary_file}" << EOF
|
||||
============================================================
|
||||
NAS Services - Installation Summary
|
||||
============================================================
|
||||
|
||||
Installation Date: $(date)
|
||||
System IP Address: ${ip_address}
|
||||
Admin User: ${ADMIN_USER:-$USER}
|
||||
SSH Port: ${SSH_PORT:-$DEFAULT_SSH_PORT}
|
||||
|
||||
------------------------------------------------------------
|
||||
Installed Services and Access Information:
|
||||
------------------------------------------------------------
|
||||
|
||||
SSH Access:
|
||||
- Host: ${ip_address}
|
||||
- Port: ${SSH_PORT:-$DEFAULT_SSH_PORT}
|
||||
- User: ${ADMIN_USER:-$USER}
|
||||
- Command: ssh -p ${SSH_PORT:-$DEFAULT_SSH_PORT} ${ADMIN_USER:-$USER}@${ip_address}
|
||||
|
||||
EOF
|
||||
|
||||
# Add service information to file
|
||||
if [[ "${INSTALL_NETDATA:-false}" == "true" ]]; then
|
||||
cat >> "${summary_file}" << EOF
|
||||
Netdata Monitoring:
|
||||
- URL: http://${ip_address}:${NETDATA_PORT}
|
||||
- Description: Real-time system monitoring and metrics
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_JELLYFIN:-false}" == "true" ]]; then
|
||||
cat >> "${summary_file}" << EOF
|
||||
Jellyfin Media Server:
|
||||
- Web Interface: http://${ip_address}:8096
|
||||
- HTTPS Interface: http://${ip_address}:8920
|
||||
- DLNA Port: ${ip_address}:1900 (UDP)
|
||||
- Description: Media streaming and management server
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_PORTAINER:-false}" == "true" ]]; then
|
||||
cat >> "${summary_file}" << EOF
|
||||
Portainer Docker Management:
|
||||
- HTTP Interface: http://${ip_address}:9000
|
||||
- HTTPS Interface: https://${ip_address}:9443
|
||||
- Description: Web-based Docker container management
|
||||
- Note: Use HTTPS (9443) for secure access
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_VAULTWARDEN:-false}" == "true" ]]; then
|
||||
cat >> "${summary_file}" << EOF
|
||||
Vaultwarden Password Manager:
|
||||
- URL: http://${ip_address}:8080
|
||||
- Description: Bitwarden-compatible password manager
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_WEBMIN:-false}" == "true" ]]; then
|
||||
cat >> "${summary_file}" << EOF
|
||||
Webmin System Administration:
|
||||
- URL: https://${ip_address}:10000
|
||||
- Description: Web-based system administration interface
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [[ "${INSTALL_NFS:-false}" == "true" ]]; then
|
||||
cat >> "${summary_file}" << EOF
|
||||
NFS Server:
|
||||
- Port: ${ip_address}:2049
|
||||
- Description: Network File System for Unix/Linux clients
|
||||
- Mount example: mount -t nfs ${ip_address}:/srv/nfs /mnt/nfs
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Samba information
|
||||
cat >> "${summary_file}" << EOF
|
||||
Samba File Sharing:
|
||||
- Ports: ${ip_address}:139 (TCP), ${ip_address}:445 (TCP), ${ip_address}:137-138 (UDP)
|
||||
- Description: Windows file sharing (SMB/CIFS)
|
||||
- Access: \\\\${ip_address} or smb://${ip_address}
|
||||
|
||||
EOF
|
||||
|
||||
# Docker information if installed
|
||||
if [[ "${INSTALL_DOCKER:-false}" == "true" ]]; then
|
||||
cat >> "${summary_file}" << EOF
|
||||
Docker:
|
||||
- Status: Installed and running
|
||||
- Socket: /var/run/docker.sock
|
||||
- Description: Container runtime for additional services
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat >> "${summary_file}" << EOF
|
||||
------------------------------------------------------------
|
||||
System Information:
|
||||
------------------------------------------------------------
|
||||
- Configuration file: ${CONFIG_FILE}
|
||||
- Installation log: ${LOG_FILE}
|
||||
- System distribution: ${DISTRO_NAME} ${DISTRO_VERSION}
|
||||
- Kernel: $(uname -r)
|
||||
|
||||
------------------------------------------------------------
|
||||
Security Notes:
|
||||
------------------------------------------------------------
|
||||
- Firewall is active and configured
|
||||
- Fail2ban is monitoring for suspicious activity
|
||||
- SSH uses Ed25519 keys for enhanced security
|
||||
- Root login via SSH is disabled
|
||||
EOF
|
||||
|
||||
if [[ "${ENABLE_AUTO_UPDATES:-false}" == "true" ]]; then
|
||||
echo "- Automatic security updates are enabled" >> "${summary_file}"
|
||||
else
|
||||
echo "- Automatic updates are disabled (manual updates recommended)" >> "${summary_file}"
|
||||
fi
|
||||
|
||||
cat >> "${summary_file}" << EOF
|
||||
|
||||
------------------------------------------------------------
|
||||
Next Steps:
|
||||
------------------------------------------------------------
|
||||
1. Reboot the system to ensure all changes take effect
|
||||
2. Review the services above and access them using the provided URLs
|
||||
3. Configure user accounts and permissions for file sharing
|
||||
4. Set up backups for your important data
|
||||
5. Regularly check system logs and monitoring
|
||||
|
||||
============================================================
|
||||
EOF
|
||||
|
||||
log_success "Services summary saved to: ${summary_file}"
|
||||
log_info "You can view this file with: cat ${summary_file}"
|
||||
|
||||
echo
|
||||
log_info "Next steps:"
|
||||
echo " 1. Reboot the system to ensure all changes take effect"
|
||||
echo " 2. Access your NAS via SSH on port ${SSH_PORT:-$DEFAULT_SSH_PORT}"
|
||||
echo " 3. Configure file shares through Samba"
|
||||
echo " 4. Review firewall rules with: sudo ufw status"
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
echo " 4. Review firewall rules with: sudo ufw status"
|
||||
;;
|
||||
fedora|opensuse)
|
||||
echo " 4. Review firewall rules with: sudo firewall-cmd --list-all"
|
||||
;;
|
||||
*)
|
||||
echo " 4. Review firewall rules (check system documentation for your firewall tool)"
|
||||
;;
|
||||
esac
|
||||
echo " 5. Check the services summary file: cat ${summary_file}"
|
||||
echo
|
||||
log_warning "Important: Please save the following information:"
|
||||
echo " - SSH Port: ${SSH_PORT:-$DEFAULT_SSH_PORT}"
|
||||
echo " - Admin User: ${ADMIN_USER:-$NEW_USER}"
|
||||
echo " - Admin User: ${ADMIN_USER:-$USER}"
|
||||
echo " - Configuration saved in: ${CONFIG_FILE}"
|
||||
echo " - Installation log: ${LOG_FILE}"
|
||||
echo " - Services summary: ${summary_file}"
|
||||
}
|
||||
|
||||
# Main script execution
|
||||
@@ -380,6 +804,9 @@ main() {
|
||||
check_system_requirements
|
||||
get_system_info
|
||||
|
||||
# Unset any existing config variables to ensure clean state
|
||||
unset INSTALL_DOCKER INSTALL_NFS INSTALL_NETDATA INSTALL_VAULTWARDEN INSTALL_JELLYFIN INSTALL_PORTAINER INSTALL_WEBMIN CONFIGURE_STATIC_IP SSH_PORT ADMIN_USER
|
||||
|
||||
# Configuration
|
||||
load_or_create_config
|
||||
|
||||
@@ -392,11 +819,18 @@ main() {
|
||||
|
||||
# Main installation
|
||||
log_info "Starting installation process..."
|
||||
|
||||
# Run apt cleanup only for apt-based distributions
|
||||
if [[ "$DISTRO" == "ubuntu" || "$DISTRO" == "debian" ]]; then
|
||||
preflight_apt_cleanup
|
||||
fi
|
||||
|
||||
update_system
|
||||
run_installation
|
||||
|
||||
# Cleanup and summary
|
||||
cleanup
|
||||
restart_all_services
|
||||
optimize_nas_performance
|
||||
perform_health_check
|
||||
show_installation_summary
|
||||
|
||||
@@ -7,6 +7,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${SCRIPT_DIR}/../config/defaults.sh"
|
||||
source "${SCRIPT_DIR}/../lib/logging.sh"
|
||||
source "${SCRIPT_DIR}/../lib/common.sh"
|
||||
source "${SCRIPT_DIR}/../lib/detection.sh"
|
||||
|
||||
# Test configuration
|
||||
TEST_LOG_FILE="/tmp/nas_test.log"
|
||||
@@ -348,6 +349,92 @@ test_performance() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Distribution detection tests
|
||||
test_normalize_version() {
|
||||
setup_test "normalize_version"
|
||||
|
||||
# Test standard version formats
|
||||
local result=$(normalize_version "24.04.0")
|
||||
assert_equals "24.04.0" "$result" "Standard version format"
|
||||
|
||||
result=$(normalize_version "12")
|
||||
assert_equals "12.0.0" "$result" "Major version only"
|
||||
|
||||
result=$(normalize_version "41.1")
|
||||
assert_equals "41.1.0" "$result" "Major.minor format"
|
||||
|
||||
# Test Debian-style versions
|
||||
result=$(normalize_version "12 (bookworm)")
|
||||
assert_equals "12.0.0" "$result" "Debian style version"
|
||||
|
||||
# Test rolling releases
|
||||
result=$(normalize_version "rolling")
|
||||
assert_equals "9999.0.0" "$result" "Rolling release"
|
||||
|
||||
result=$(normalize_version "unstable")
|
||||
assert_equals "9999.0.0" "$result" "Unstable release"
|
||||
|
||||
# Test complex versions
|
||||
result=$(normalize_version "24.04 LTS")
|
||||
assert_equals "24.04.0" "$result" "Version with suffix"
|
||||
}
|
||||
|
||||
test_version_compare() {
|
||||
setup_test "version_compare"
|
||||
|
||||
# Test greater than or equal
|
||||
version_compare "24.04.0" ">=" "24.04.0" && assert_true $? "Equal versions with >="
|
||||
version_compare "24.04.1" ">=" "24.04.0" && assert_true $? "Higher version with >="
|
||||
version_compare "24.03.0" ">=" "24.04.0" && assert_false $? "Lower version with >="
|
||||
|
||||
# Test greater than
|
||||
version_compare "24.04.1" ">" "24.04.0" && assert_true $? "Higher version with >"
|
||||
version_compare "24.04.0" ">" "24.04.0" && assert_false $? "Equal versions with >"
|
||||
|
||||
# Test less than or equal
|
||||
version_compare "24.04.0" "<=" "24.04.0" && assert_true $? "Equal versions with <="
|
||||
version_compare "24.03.0" "<=" "24.04.0" && assert_true $? "Lower version with <="
|
||||
version_compare "24.05.0" "<=" "24.04.0" && assert_false $? "Higher version with <="
|
||||
|
||||
# Test less than
|
||||
version_compare "24.03.0" "<" "24.04.0" && assert_true $? "Lower version with <"
|
||||
version_compare "24.04.0" "<" "24.04.0" && assert_false $? "Equal versions with <"
|
||||
|
||||
# Test equal
|
||||
version_compare "24.04.0" "==" "24.04.0" && assert_true $? "Equal versions with =="
|
||||
version_compare "24.04.0" "=" "24.04.0" && assert_true $? "Equal versions with ="
|
||||
version_compare "24.04.1" "==" "24.04.0" && assert_false $? "Different versions with =="
|
||||
|
||||
# Test not equal
|
||||
version_compare "24.04.1" "!=" "24.04.0" && assert_true $? "Different versions with !="
|
||||
version_compare "24.04.0" "!=" "24.04.0" && assert_false $? "Equal versions with !="
|
||||
}
|
||||
|
||||
test_container_detection() {
|
||||
setup_test "container_detection"
|
||||
|
||||
# Test that function exists and runs without error
|
||||
# Note: On macOS, we won't detect actual containers, but the function should work
|
||||
unset CONTAINER_TYPE
|
||||
|
||||
if detect_container_environment 2>/dev/null; then
|
||||
echo " ✓ Container detection function runs without error"
|
||||
((TESTS_PASSED++))
|
||||
else
|
||||
echo " ✗ Container detection function failed"
|
||||
((TESTS_FAILED++))
|
||||
fi
|
||||
|
||||
# Test that CONTAINER_TYPE is set appropriately (should be empty on macOS)
|
||||
if [[ -z "${CONTAINER_TYPE:-}" ]]; then
|
||||
echo " ✓ No container environment detected (expected on macOS)"
|
||||
((TESTS_PASSED++))
|
||||
else
|
||||
echo " ✓ Container environment detected: $CONTAINER_TYPE"
|
||||
((TESTS_PASSED++))
|
||||
fi
|
||||
}
|
||||
|
||||
# Main test runner
|
||||
main() {
|
||||
echo "Starting NAS Setup Script Unit Tests"
|
||||
@@ -382,6 +469,15 @@ main() {
|
||||
test_performance
|
||||
echo
|
||||
|
||||
test_normalize_version
|
||||
echo
|
||||
|
||||
test_version_compare
|
||||
echo
|
||||
|
||||
test_container_detection
|
||||
echo
|
||||
|
||||
# Cleanup
|
||||
rm -f "$TEST_LOG_FILE" "$TEST_CONFIG_FILE"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user