4/8/2024
QNAP Container Station — a full Docker environment without a dedicated server
TL;DR: QNAP Container Station = Docker on a NAS. SSH on port 222, docker compose up, production containers. Docker binary path: /share/CACHEDEV1_DATA/.qpkg/container-station/bin/docker. If you already have a QNAP in your server rack, you effectively have a Linux server.
NAS is a device for storing files — that’s how most users think of it. But a QNAP with Container Station installed is a fully-fledged Docker host: run any images, map ports, mount volumes. No extra VPS, no monthly fees.
Container Station vs VPS
Let’s compare costs over a 3-year horizon for a small web project.
QNAP TS-233 (2-bay ARM NAS): about 1400 PLN one-time. Active power consumption: 25W. At a price of 0.80 PLN/kWh and 8760 hours per year: 25W × 8760h × 0.80 PLN = about 175 PLN/year. Over 3 years: 1400 + 525 = 1925 PLN.
Hetzner CX22 (2 vCPU, 4GB RAM): 6 EUR/month × 36 months = 216 EUR = about 900 PLN at current exchange rates.
VPS wins on cost — but QNAP is already in most offices and small businesses. If the device is sitting unused as a simple network drive, Container Station is a free add-on. Another NAS advantage: your data is physically with you, with no dependence on a provider’s availability.
First steps over SSH
First, enable SSH in QTS: Control Panel → Network Services → SSH → Enable (port 222). QNAP uses the non-standard port 222 instead of 22, because 22 is often occupied by another system service.
ssh admin@192.168.10.200 -p 222
On QNAP, sudo works differently than on a standard Debian system. You need to provide the password via pipe:
echo 'your-password' | sudo -S docker ps
Create your project directory in /share/Container/:
mkdir -p /share/Container/my-project
cd /share/Container/my-project
Don’t use /tmp or system paths — they survive reboots but may be cleared by QNAP during firmware updates.
Deploy script from WSL
The most convenient deploy pattern for Windows + QNAP environments is a script through WSL:
#!/bin/bash
QNAP_IP="192.168.10.200"
QNAP_USER="admin"
QNAP_PASS="your-password"
CONTAINER="my-container"
# Copy file to QNAP
sshpass -p "$QNAP_PASS" scp -P 222 ./dist.tar.gz \
"$QNAP_USER@$QNAP_IP:/tmp/dist.tar.gz"
# Upload to container
sshpass -p "$QNAP_PASS" ssh -p 222 "$QNAP_USER@$QNAP_IP" \
"docker cp /tmp/dist.tar.gz $CONTAINER:/app/dist.tar.gz && \
docker exec $CONTAINER tar -xzf /app/dist.tar.gz -C /app/ && \
rm /tmp/dist.tar.gz"
The cat file | ssh "cat > /tmp/x" pattern works for smaller files without sshpass, but for large archives scp is more reliable.
Port conflicts
QNAP QTS occupies the following ports by default: 80 and 443 (web UI), 8080 (alternative HTTP), 8081 (Container Station UI), 9000 (Portainer if installed). You need to avoid these when mapping container ports.
Safe ports for your own services: 3000–3999, 5000–5999 (except 5000 – QTS Video), 7000–7999, 8888, 9100+. My project convention: web apps on 3xxx, databases on 54xx (5432 for PostgreSQL), monitoring on 3100.
MikroTik NAT
After starting a container on QNAP, to make the service accessible from the internet, add a NAT rule on MikroTik:
/ip firewall nat add \
chain=dstnat \
protocol=tcp \
dst-port=443 \
in-interface=ether1-wan \
action=dst-nat \
to-addresses=192.168.10.200 \
to-ports=3443 \
comment="QNAP container HTTPS"
Remember to also configure hairpin NAT (separate article) if you want to access this service using the public domain from devices inside the LAN.
Summary
QNAP Container Station is an underrated Docker hosting solution. If you already have a NAS in your infrastructure, spinning up another container costs a few lines of configuration. Key details: SSH port 222, non-standard Docker binary path, sudo via pipe, project directories in /share/Container/. It doesn’t replace the flexibility of a VPS under heavy traffic, but for hobby and small production projects — it’s more than enough.