Deploy › VPS (sudo / Docker)¶
Guida per VPS Linux generico con privilegi sudo: Debian/Ubuntu/Arch/qualsiasi distro con systemd. Se sei su Ultra.cc vai invece alla guida Ultra.cc: niente sudo e nginx user-proxy.
Copriamo due scenari:
- Nativo con systemd + nginx + Let's Encrypt (consigliato — meno overhead, più controllo).
- Docker / docker-compose (se preferisci container).
1 — Prerequisiti di sistema¶
Debian/Ubuntu:
sudo apt update
sudo apt install -y python3 python3-venv python3-pip \
libmediainfo0v5 \
nginx git \
certbot python3-certbot-nginx
Crea un utente dedicato (evita di far girare servizi come root):
sudo adduser --system --group --shell /bin/bash --home /opt/unit3dprep unit3dprep
sudo -u unit3dprep -i
Tutti i passi successivi come utente unit3dprep se non specificato altrimenti.
2 — Installa l'applicazione¶
cd ~
git clone https://github.com/davidesidoti/unit3dprep.git
cd unit3dprep
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
pip install unit3dup # uploader richiesto nel PATH
Genera hash password e secret:
Copia l'output in un file env che systemd leggerà (vedi step 3).
Crea le cartelle:
mkdir -p ~/media/{movies,series,anime} ~/seedings
df ~/media ~/seedings # verifica stesso filesystem
3 — Systemd unit¶
Crea /etc/systemd/system/unit3dprep.service:
[Unit]
Description=unit3dprep web UI
After=network-online.target
Wants=network-online.target
[Service]
Type=exec
User=unit3dprep
Group=unit3dprep
WorkingDirectory=/opt/unit3dprep/unit3dprep
EnvironmentFile=/opt/unit3dprep/unit3dprep.env
ExecStart=/opt/unit3dprep/unit3dprep/.venv/bin/unit3dprep-web
Restart=on-failure
RestartSec=5
# Hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/opt/unit3dprep
[Install]
WantedBy=multi-user.target
Crea /opt/unit3dprep/unit3dprep.env (modo 600):
U3DP_PASSWORD_HASH=$2b$12$...
U3DP_SECRET=...
TMDB_API_KEY=...
U3DP_HOST=127.0.0.1
U3DP_PORT=8765
U3DP_HTTPS_ONLY=1
sudo chown unit3dprep:unit3dprep /opt/unit3dprep/unit3dprep.env
sudo chmod 600 /opt/unit3dprep/unit3dprep.env
Abilita e avvia:
sudo systemctl daemon-reload
sudo systemctl enable --now unit3dprep.service
sudo systemctl status unit3dprep.service
journalctl -u unit3dprep.service -f
4 — Nginx reverse proxy + HTTPS¶
/etc/nginx/sites-available/unit3dprep.conf:
server {
listen 80;
server_name unit3dprep.example.com;
# Certbot temporanea — lascia che certbot gestisca
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name unit3dprep.example.com;
# Certificati popolati da certbot
ssl_certificate /etc/letsencrypt/live/unit3dprep.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/unit3dprep.example.com/privkey.pem;
# SSE-friendly timeouts e buffering
proxy_buffering off;
proxy_read_timeout 1h;
# Upload grandi consentiti
client_max_body_size 4g;
location / {
proxy_pass http://127.0.0.1:8765;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Connection ""; # needed for SSE / keep-alive
}
}
Abilita + ottieni il certificato:
sudo ln -s /etc/nginx/sites-available/unit3dprep.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d unit3dprep.example.com
Sottopath vs root
L'esempio serve sotto la root del dominio. Se vuoi un sottopath (es. unit3dprep.example.com/unit3dprep/), aggiungi uno slash al proxy_pass (proxy_pass http://127.0.0.1:8765/;) così nginx strippa il prefisso → lascia U3DP_ROOT_PATH="". Oppure mantieni nginx che non strippa (senza slash finale) e imposta U3DP_ROOT_PATH=/unit3dprep.
5 — Firewall¶
Lascia chiusa la porta 8765: il servizio ascolta solo su 127.0.0.1.
6 — Backup¶
File da backuppare periodicamente (solo l'utente unit3dprep vi accede):
/opt/unit3dprep/unit3dprep.env # secret
~/Unit3Dup_config/Unit3Dbot.json # config tracker + client
~/.unit3dprep_db.json # storico upload
~/.unit3dprep_tmdb_cache.json # rigenerabile
~/.unit3dprep_lang_cache.json # rigenerabile
Esempio con rsync + cron:
7 — Aggiornamenti¶
sudo -u unit3dprep -i
cd ~/unit3dprep
git pull
source .venv/bin/activate
pip install -e .
exit
sudo systemctl restart unit3dprep.service
Se hai toccato il frontend devi ricompilarlo (richiede Node):
Variante Docker¶
Esempio minimo Dockerfile (non incluso nel repo — aggiungilo se ti serve):
FROM python:3.11-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends libmediainfo0v5 git \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -e . unit3dup
ENV U3DP_HOST=0.0.0.0 \
U3DP_PORT=8765
EXPOSE 8765
CMD ["unit3dprep-web"]
docker-compose.yml:
services:
unit3dprep:
build: .
restart: unless-stopped
ports:
- "127.0.0.1:8765:8765"
environment:
U3DP_PASSWORD_HASH: ${U3DP_PASSWORD_HASH}
U3DP_SECRET: ${U3DP_SECRET}
TMDB_API_KEY: ${TMDB_API_KEY}
U3DP_HTTPS_ONLY: "1"
volumes:
- ./media:/root/media:ro
- ./seedings:/root/seedings
- ./unit3dup-config:/root/Unit3Dup_config
- unit3dprep-data:/root
volumes:
unit3dprep-data:
Hardlink e Docker
Gli hardlink funzionano solo nello stesso volume. Se monti media e seedings come bind mount separati, l'hardlink fallisce. Usa un singolo volume che contiene entrambe le sottocartelle, oppure monta la stessa cartella host che contiene media/ e seedings/.
Proxy davanti a Docker: gestisci TLS con Caddy / Traefik / nginx esterno che puntano a 127.0.0.1:8765.
Checklist post-deploy¶
- [ ]
systemctl status unit3dprep.service→active (running) - [ ]
https://unit3dprep.example.comrisponde, login funziona - [ ]
journalctl -u unit3dprep-web -f→ nessun errore - [ ]
GET /api/settings/fs-check→same_fs: true - [ ] Un upload di test completa end-to-end
- [ ] Backup automatico configurato
- [ ]
certbot renew --dry-run→ successo