Blog
SysAdmin
Linux
NAS
]
![]()
When discussing NAS solutions, most people think of “a box with disks that shares files.” In practice, a modern NAS is much more than that. This part covers configuring all key services: Samba, ownCloud, Nginx, and WireGuard VPN.
This is part 3 of the “Building Your Own NAS” series, originally published on root.cz. S1: Hardware & OS · S2: Custom Case & Data Migration · S3: Service Configuration · S4: Monitoring · S5: Security & Firewall
My requirements for a functional NAS:
apt install samba
The main configuration file is /etc/samba/smb.conf. Key global settings include:
standalone serveruser (user-based authentication)This uses Samba 4.19.5, where older protocols like SMBv1 are disabled by default — a security improvement.
Three primary share types:
1. Home directories — password-protected, restricted to the sambausers group:
[homes]
comment = Home Directories
browseable = no
read only = no
create mask = 0700
directory mask = 0700
valid users = %S
2. Multimedia — public media sharing with guest access:
[multimedia]
comment = Multimedia
path = /nas/multimedia
guest ok = yes
read only = yes
browseable = yes
3. Backup — non-browseable backup storage:
[backup]
comment = Backup
path = /nas/backup
browseable = no
valid users = @sambausers
Optional but convenient:
avahi-daemon for mDNS/Bonjour discoverywsdd for Windows Service DiscoveryDocker containerization is used with a simple principle: each application has its own directory containing docker-compose.yml, managed by a universal systemd service template.
Create /etc/systemd/system/dc@.service:
[Unit]
Description=Docker Compose service: %i
After=docker.service network-online.target
Requires=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/containers/%i
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
[Install]
WantedBy=multi-user.target
This template enables consistent deployment of complex multi-container applications without requiring Kubernetes or similar orchestration. To deploy any application:
systemctl enable dc@owncloud.service
systemctl start dc@owncloud.service
ownCloud was selected over Nextcloud — appropriately featured without unnecessary complexity. It provides essential functionality for data access and sharing while maintaining simplicity.
/containers/owncloud/
├── docker-compose.yml
└── .env
/var/lib/containers-data/owncloud/
├── server/
├── db/
└── dbbackup/
The docker-compose.yml defines three services:
Each has appropriate volume bindings, environment variables sourced from .env, and health checks.
The .env file stores sensitive credentials:
OC_VERSION=10.15
DOMAIN=nas.example.com
ADMIN_PASSWORD=changeme
DB_PASSWORD=changeme
HTTP_PORT=8080
The External Storage feature in ownCloud is used to mount directories from Samba shares into user spaces. This approach has several advantages:
Administrators enable External Storage in ownCloud admin panel:

Users then connect their own Samba share in personal settings:

The resulting user file view:

# Binary backup using mariadb-backup
docker exec owncloud-mariadb mariadb-backup \
--backup --target-dir=/backup/$(date +%F)
# SQL dump
docker exec owncloud-mariadb mariadb-dump \
--all-databases > /backup/dump-$(date +%F).sql
Backups are stored in /backup/ (mapped to /var/lib/containers-data/owncloud/dbbackup), with Restic handling broader backup of the entire containers data directory.
Containerized applications run on port 8080. Nginx serves as the main reverse proxy and TLS terminator — individual applications don’t need to manage certificates.
apt install nginx
Due to router limitations, port 8443 is used instead of standard 443. Router port forwarding:
80 → NAS:80 (required for Certbot’s http-01 challenge)8443 → NAS:443Prerequisites before acquiring a certificate:
Install Certbot following the official documentation.
Create a virtual host, then run:
certbot --nginx -m your@email
Certbot automatically detects configuration, updates Nginx, and sets up automatic certificate renewal via cron or systemd.timer.
A location block proxies requests to the ownCloud container with appropriate header forwarding:
server {
listen 443 ssl;
server_name nas.example.com;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 8443;
}
}
The X-Forwarded-Proto and X-Forwarded-Port headers ensure ownCloud recognizes the correct external interface.
WireGuard was selected for its straightforward, uncomplicated implementation.
wg genkey | tee wg-private | wg pubkey > wg-public
chmod 0600 wg-private
/etc/wireguard/wg0.conf:
[Interface]
Address = 10.1.0.1/24
ListenPort = 51820
PrivateKey = <server-private-key>
# Allow VPN clients to reach the internal LAN and route traffic through NAS
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; \
iptables -A FORWARD -o wg0 -j ACCEPT; \
iptables -t nat -A POSTROUTING -o enp1s0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; \
iptables -D FORWARD -o wg0 -j ACCEPT; \
iptables -t nat -D POSTROUTING -o enp1s0 -j MASQUERADE
[Peer]
# Client 1 — Phone
PublicKey = <client1-public-key>
AllowedIPs = 10.1.0.2/32
[Peer]
# Client 2 — Laptop
PublicKey = <client2-public-key>
AllowedIPs = 10.1.0.3/32
Replace interface names (enp1s0) to match your specific network configuration.
wg
Displays connection status including peer endpoints, allowed IPs, handshake timestamps, and traffic statistics.
Enable and start:
systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0
In the next chapter, we’ll set up comprehensive monitoring with Telegraf, InfluxDB, Grafana, and email notifications.