Docker uruchamia aplikacje w izolowanych kontenerach, które niosą ze sobą wszystko, czego potrzebują. Zainstalujemy go z oficjalnego repozytorium, przez Docker Compose uruchomimy WordPress z bazą danych i przejdziemy przez zarządzanie, aktualizacje, firewall i kopie zapasowe.
Czego potrzebujesz
- VPS w StormHost z Ubuntu 24.04 lub Debianem 13
- Połączenie SSH jako root (poradnik)
- Dla WordPressa z HTTPS domena skierowana na VPS
- Około 25 minut
Jak to działa#
| Pojęcie | Co to jest |
|---|---|
| Obraz | Gotowy szablon aplikacji: biblioteki systemowe, program i jego ustawienia. Pobierany z rejestru, najczęściej Docker Hub (na przykład wordpress, mariadb). |
| Kontener | Działająca instancja obrazu. Ma własny system plików i sieć, ale dzieli jądro z VPS. Kontener możesz w dowolnej chwili usunąć i utworzyć ponownie z tego samego obrazu. |
| Wolumen | Trwałe miejsce na dane poza kontenerem. Dane w wolumenie przetrwają usunięcie i aktualizację kontenera. Wszystko, co chcesz zachować, musi być w wolumenie. |
| Port | Kontener ma własną sieć. Aby był dostępny z zewnątrz, jego port jest „publikowany” na porcie VPS. |
| Docker Compose | Narzędzie uruchamiające całą wielokontenerową aplikację (na przykład stronę i bazę danych) z jednego pliku compose.yaml. |
Instalacja#
Zainstaluj Dockera z oficjalnego repozytorium Dockera. Pakiet docker.io z repozytorium dystrybucji bywa starszy i koliduje z oficjalnymi pakietami.
Najpierw usuń ewentualne kolidujące pakiety. Na świeżym VPS polecenie niczego nie znajdzie, co jest w porządku.
Ubuntu 24.04
apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc | cut -f1)Debian 13
apt remove $(dpkg --get-selections docker.io docker-compose docker-doc docker-buildx podman-docker containerd runc | cut -f1)dpkg --get-selections …– wypisuje, które z podanych pakietów są zainstalowane.| cut -f1– zostawia tylko nazwy pakietów.apt remove $(…)– odinstalowuje je. Dane w/var/lib/dockerzostają.
Następnie dodaj repozytorium Dockera i zainstaluj Dockera:
Ubuntu 24.04
apt update
apt -y install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
apt update
apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginDebian 13
apt update
apt -y install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
apt update
apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginCo robi każda linia:
| Polecenie | Co robi |
|---|---|
apt -y install ca-certificates curl | Certyfikaty dla HTTPS i narzędzie do pobierania. |
install -m 0755 -d /etc/apt/keyrings | Tworzy katalog na klucze podpisujące repozytoriów z uprawnieniami 0755. |
curl -fsSL …/gpg -o /etc/ | Pobiera klucz podpisujący Dockera. -f = błąd przy błędach HTTP, -s = cicho, -S = mimo to pokazuj błędy, -L = podążaj za przekierowaniami. |
chmod a+r …/docker.asc | Każdy może czytać klucz (apt czyta go jako inny użytkownik). |
tee /etc/ | Zapisuje definicję repozytorium do pliku. |
Types: deb | Repozytorium z pakietami binarnymi. |
URIs: | Adres repozytorium dla Twojego systemu. |
Suites: $(…) | Nazwa kodowa systemu (noble dla Ubuntu 24.04, trixie dla Debiana 13), wypełniana automatycznie. |
Components: stable | Tylko wydania stabilne. |
Architectures: $(dpkg --print-architecture) | Architektura CPU (amd64). |
Signed-By: | Pakiety muszą być podpisane tym kluczem, inaczej apt je odrzuca. |
apt -y install docker-ce … | Instaluje Docker Engine (docker-ce), wiersz poleceń (docker-ce-cli), środowisko kontenerów (containerd.io), budowanie obrazów (docker-buildx-plugin) i Compose (docker-compose-plugin). |
Po instalacji Docker startuje sam i jest włączony przy uruchomieniu VPS. Sprawdź instalację:
docker run --rm hello-world
docker compose versiondocker run --rm hello-world– pobiera obraz testowy i go uruchamia;--rmusuwa kontener po zakończeniu. ZobaczyszHello from Docker!.docker compose version– wypisuje wersję Compose, na przykładDocker Compose version v5.…. Po wersji 2 Compose przeskoczył od razu na 5, więc starsze instalacje pokazująv2.…. Polecenia w tym poradniku działają z obiema.
Grupa docker = uprawnienia roota
Każdy w grupie docker może uruchamiać kontenery z dostępem do całego dysku VPS, co w praktyce oznacza uprawnienia roota. Dodawaj tylko osoby, którym dałbyś także roota. Jeśli pracujesz jako root, grupy nie potrzebujesz.
Pierwsza aplikacja: WordPress z MariaDB#
Projekt i hasła#
Utwórz katalog projektu i przejdź do niego:
bash mkdir -p /opt/wordpress cd /opt/wordpressNazwa katalogu (
wordpress) staje się nazwą projektu Compose i prefiksem nazw kontenerów i wolumenów.Utwórz plik z hasłami przez
nano .env. Hasła wygeneruj generatorem haseł (tylko litery i cyfry):/opt/ wordpress/ ini.env DB_PASSWORD=<HASLO_BAZY_DANYCH> DB_ROOT_PASSWORD=<HASLO_ROOT_BAZY_DANYCH>DB_PASSWORD– hasło użytkownika bazy danych WordPressa.DB_ROOT_PASSWORD– hasło użytkownika root wewnątrz kontenera bazy danych (do kopii zapasowych i administracji).
Ustaw plik jako czytelny tylko dla roota:
bash chmod 600 .env
Plik compose.yaml#
Utwórz nano compose.yaml z tą zawartością:
services:
db:
image: mariadb:lts
restart: unless-stopped
environment:
MARIADB_DATABASE: wordpress
MARIADB_USER: wordpress
MARIADB_PASSWORD: ${DB_PASSWORD}
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
start_period: 10s
interval: 10s
timeout: 5s
retries: 3
wordpress:
image: wordpress:latest
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "127.0.0.1:8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
WORDPRESS_DB_NAME: wordpress
volumes:
- wp_data:/var/www/html
volumes:
db_data:
wp_data:Linia po linii:
| Linia | Co robi |
|---|---|
services: | Lista kontenerów aplikacji. Nazwa usługi (db, wordpress) służy też jako jej nazwa hosta w sieci projektu. |
image: mariadb:lts | Oficjalny obraz MariaDB; tag lts = najnowsze wydanie z długim wsparciem. |
restart: unless-stopped | Kontener startuje ponownie po awarii i po restarcie VPS, chyba że zatrzymano go ręcznie. |
MARIADB_DATABASE, MARIADB_USER, MARIADB_PASSWORD | Przy pierwszym starcie tworzy bazę danych i użytkownika z hasłem. |
MARIADB_ROOT_PASSWORD | Hasło roota bazy danych, ustawiane przy pierwszym starcie. |
${DB_PASSWORD} | Wartość jest uzupełniana z pliku .env w tym samym katalogu, więc hasła nie są wpisane bezpośrednio w compose.yaml. |
volumes: - db_data:/var/lib/mysql | Dane bazy są przechowywane w wolumenie db_data, więc przetrwają aktualizacje kontenera. |
healthcheck: | Co 10 s Docker skryptem healthcheck.sh z obrazu MariaDB sprawdza, czy baza przyjmuje połączenia i jest zainicjalizowana. |
depends_on: db: condition: service_healthy | WordPress startuje dopiero, gdy baza danych jest gotowa. |
image: wordpress:latest | Oficjalny obraz WordPressa (Apache + PHP). |
ports: - "127.0.0.1:8080:80" | Port 80 kontenera jest dostępny na porcie 8080 VPS, ale tylko z samego VPS (127.0.0.1). Z zewnątrz dostępny tylko przez Nginx. |
WORDPRESS_DB_HOST: db | Adres bazy danych: nazwa usługi db w sieci projektu. |
WORDPRESS_DB_USER, …_PASSWORD, …_NAME | Dane logowania do bazy; muszą zgadzać się z wartościami usługi db. |
volumes: - wp_data:/var/www/html | Pliki WordPressa (pluginy, motywy, przesłane obrazy) są w wolumenie wp_data. |
volumes: na końcu | Deklaruje nazwane wolumeny używane przez projekt. |
Uruchomienie#
docker compose up -d
docker compose psdocker compose up -d– pobiera obrazy, tworzy sieć, wolumeny i kontenery i uruchamia je w tle (-d, detached).docker compose ps– wypisuje kontenery projektu i ich status.dbpokazujehealthy,wordpresspokazujeUp.
Kontrola z VPS: curl -I http://127.0.0.1:8080 zwraca nagłówki odpowiedzi WordPressa (przekierowanie do instalatora).
Zmienne MARIADB_* działają tylko przy pierwszym starcie
Baza danych powstaje przy pierwszym starcie z pustym wolumenem. Późniejsza zmiana hasła w .env nie zmienia go w bazie. Zmień hasło w bazie przez ALTER USER (zobacz MariaDB na VPS) i dopiero potem w .env.
Udostępnienie przez Nginx i HTTPS#
WordPress nasłuchuje teraz tylko na 127.0.0.1:8080. Udostępnij go przez Nginx jako reverse proxy według poradnika Nginx i HTTPS: w konfiguracji użyj proxy_pass http://127.0.0.1:8080; i swojej domeny, na przykład blog.example.cz, a potem uzyskaj certyfikat przez certbot --nginx -d blog.example.cz.
Obraz WordPressa sam wykrywa HTTPS z nagłówka X-Forwarded-Proto, który Nginx wysyła po skonfigurowaniu jak w tamtym poradniku. Na koniec otwórz https://blog.example.cz i dokończ instalację WordPressa w przeglądarce.
Zarządzanie kontenerami#
Polecenia docker compose uruchamiaj w katalogu projektu (cd /opt/wordpress).
| Polecenie | Co robi |
|---|---|
docker compose ps | Status kontenerów projektu. |
docker compose logs -f | Logi wszystkich usług; -f = śledzenie na żywo (zatrzymaj przez Ctrl+C). Tylko jedna usługa: docker compose logs -f wordpress. |
docker compose restart | Restartuje kontenery. |
docker compose stop / start | Zatrzymuje / uruchamia kontenery bez usuwania czegokolwiek. |
docker compose up -d | Po zmianie compose.yaml odtwarza tylko zmienione kontenery. |
docker compose down | Zatrzymuje i usuwa kontenery i sieć. Wolumeny z danymi zostają. |
docker compose exec db mariadb -uroot -p | Wykonuje polecenie wewnątrz działającego kontenera (tutaj konsola MariaDB). |
docker compose config | Sprawdza compose.yaml i wypisuje go z uzupełnionymi wartościami z .env (uwaga, pokazuje też hasła). |
Aktualizacja do nowych wersji obrazów:
docker compose pull
docker compose up -d
docker image prune -fdocker compose pull– pobiera nowe wersje obrazów.docker compose up -d– odtwarza kontenery, które mają nowszy obraz. Dane w wolumenach zostają.docker image prune -f– usuwa stare, nieużywane już obrazy;-fpomija potwierdzenie.
docker compose down -v usuwa dane
Flaga -v polecenia docker compose down usuwa także wolumeny projektu, czyli bazę danych i pliki WordPressa. Nie da się tego cofnąć. Używaj jej tylko wtedy, gdy chcesz całkowicie usunąć aplikację i masz kopię zapasową.
Opcje restart::
| Wartość | Kiedy kontener startuje ponownie |
|---|---|
no | Nigdy (domyślnie). |
always | Zawsze, nawet po ręcznym zatrzymaniu (po restarcie Dockera lub VPS). |
on-failure | Tylko gdy kończy się błędem. |
unless-stopped | Zawsze, poza przypadkiem, gdy zatrzymano go ręcznie. Zalecane dla usług. |
Porty i firewall#
Docker publikuje porty kontenerów własnymi regułami firewalla, które omijają UFW. Port opublikowany jako 8080:80 jest dostępny z internetu, nawet jeśli nie zezwolisz na niego w UFW. Szczegółowo wyjaśnia to poradnik Firewall UFW.
Wpis w ports: | Kto może dotrzeć do portu |
|---|---|
"8080:80" | Każdy w internecie, niezależnie od UFW. |
"127.0.0.1:8080:80" | Tylko procesy na VPS (na przykład Nginx). Zalecane dla stron za Nginx. |
brak ports: | Tylko inne kontenery w tej samej sieci projektu (zwykle bazy danych). |
Baz danych i innych usług wewnętrznych w ogóle nie publikuj. Porty, które muszą być publiczne (na przykład serwer gier w kontenerze), ogranicz firewallem w strefie klienta (poradnik). Znajduje się przed VPS i Docker nie może go ominąć.
Zwalnianie miejsca na dysku#
Obrazy, zatrzymane kontenery i logi zajmują z czasem dużo miejsca.
docker system df
docker system prunedocker system df– ile miejsca zajmują obrazy, kontenery, wolumeny i cache.docker system prune– po potwierdzeniu usuwa zatrzymane kontenery, nieużywane sieci, obrazy bez tagu i cache budowania. Nie usuwa wolumenów z danymi, chyba że dodasz--volumes.
Ostrożnie z usuwaniem wolumenów i z -a
docker system prune --volumes usuwa także nieużywane wolumeny anonimowe (bez nazwy, tworzone na przykład przez docker run bez -v). Jeśli trzymały dane kontenera, który jest właśnie usunięty lub zatrzymany, te dane przepadają. docker volume prune -a usuwa też wolumeny nazwane, jak wordpress_db_data, gdy nie używa ich żaden kontener, na przykład po docker compose down. docker system prune -a usuwa wszystkie obrazy, których nie używa żaden kontener. Przed potwierdzeniem przeczytaj, co polecenie zamierza usunąć.
Domyślnie logi kontenerów nie są rotowane i mogą zapełnić dysk. Ustaw sterownik local, który sam usuwa stare logi (domyślnie trzyma najwyżej 5 plików po 20 MB na kontener). Utwórz plik nano /etc/docker/daemon.json z poniższą zawartością. Jeśli plik już istnieje, nie nadpisuj go; dodaj tylko linię "log-driver" (wpisy oddzielone przecinkami):
{
"log-driver": "local"
}Następnie zrestartuj Dockera (systemctl restart docker) i odtwórz kontenery (docker compose up -d --force-recreate). Ustawienie dotyczy tylko nowo tworzonych kontenerów.
Kopie zapasowe#
Archiwizuj wolumeny, nie kontenery. Kontener odtworzysz z obrazu, ale danych nie.
Utwórz katalog na kopie zapasowe:
mkdir -p /root/zalohy.Zarchiwizuj bazę danych eksportem (bardziej spójne niż kopiowanie plików):
bash cd /opt/wordpress docker compose exec -T db sh -c 'exec mariadb-dump --single-transaction --all-databases -uroot -p"$MARIADB_ROOT_PASSWORD"' > /root/zalohy/wp-db-$(date +%F).sqldocker compose exec -T db– wykonuje polecenie w kontenerzedb;-Twyłącza terminal, aby wyjście dało się przekierować do pliku.sh -c '…'– polecenie działa w powłoce kontenera, gdzie ustawiona jest zmienna$MARIADB_ROOT_PASSWORD.mariadb-dump --single-transaction --all-databases– eksportuje wszystkie bazy bez blokowania.> /root/zalohy/…– wyjście zapisuje się na VPS, poza kontenerem.
Zarchiwizuj pliki WordPressa, pakując wolumen:
bash docker run --rm -v wordpress_wp_data:/data:ro -v /root/zalohy:/backup alpine tar czf /backup/wp-files-$(date +%F).tar.gz -C /data .docker run --rm– uruchamia jednorazowy kontener, usuwany po zakończeniu.-v wordpress_– montuje wolumenwp_ data:/ data: ro wp_dataprojektuwordpresstylko do odczytu (ro).-v /root/zalohy:/backup– montuje katalog kopii zapasowych z VPS.alpine tar czf … -C /data .– pakuje zawartość wolumenu do archiwum przy użyciu małego obrazu Alpine.
docker volume lswypisuje dokładne nazwy wolumenów.
Automatyczne kopie zapasowe przez cron i kopiowanie ich poza VPS opisuje artykuł Kopie zapasowe na VPS.
Weryfikacja#
docker compose pspokazuje oba kontenery jako działające, a bazę danych jakohealthy.https://blog.example.czpokazuje WordPressa z kłódką w pasku adresu.- Po restarcie VPS (
reboot) kontenery startują same. - Z innego komputera nie da się połączyć z
http://(port jest przypięty tylko do<ADRES_ IP_ VPS>: 8080 127.0.0.1).
Rozwiązywanie problemów#
permission denied while trying to connect to the Docker daemon socket#
Nie jesteś rootem, a Twój użytkownik nie jest w grupie docker. Uruchom polecenie z sudo albo zaloguj się jako root.
Bind for 127.0.0.1:8080 failed: port is already allocated lub address already in use#
Port 8080 zajmuje już inny kontener (pierwszy komunikat) albo inny program na VPS (drugi komunikat). Ustal który (ss -tlnp | grep 8080, docker ps) i wybierz inny port w compose.yaml, na przykład 127.0.0.1:8081:80. Potem zaktualizuj także proxy_pass w Nginx.
WordPress pokazuje „Error establishing a database connection”#
Baza danych nie jest jeszcze gotowa albo dane logowania się nie zgadzają. Sprawdź log bazy (docker compose logs db). Jeśli zmieniono hasło w .env po pierwszym starcie, baza nadal ma stare hasło (zobacz ostrzeżenie w sekcji Uruchomienie).
Kontener stale pokazuje Restarting#
Aplikacja w kontenerze zawiesza się zaraz po starcie. Przyczynę znajdziesz w logu: docker compose logs --tail 50 <NAZWA_USLUGI>.
toomanyrequests: You have reached your unauthenticated pull rate limit#
Docker Hub ogranicza anonimowe pobieranie obrazów do 100 na 6 godzin na adres IP. Poczekaj albo zaloguj się kontem Docker Hub: docker login.
no space left on device#
Dysk jest pełny. Sprawdź, co go zajmuje (docker system df, df -h), i posprzątaj zgodnie z sekcją Zwalnianie miejsca na dysku. Jeśli miejsca naprawdę brakuje, zwiększ RAM w zakładce Zmiana pakietu; rozmiar dysku rośnie razem z pamięcią.
Podsumowanie
- Dockera instaluj z oficjalnego repozytorium
download.docker.com, nie z pakietudocker.io. - Dane należą do wolumenów; kontenery można w dowolnej chwili usuwać i odtwarzać.
- Strony publikuj na
127.0.0.1i udostępniaj przez Nginx z HTTPS; inaczej Docker omija UFW. - Aktualizacje:
docker compose pullidocker compose up -d. docker compose down -viprune --volumesusuwają dane; regularnie archiwizuj wolumeny.
Dalsza lektura#
- Docker: instalacja Docker Engine na Ubuntu (otwiera się w nowym oknie)
- Docker: instalacja Docker Engine na Debianie (otwiera się w nowym oknie)
- Docker: filtrowanie pakietów i firewalle (otwiera się w nowym oknie)
- Docker: publikowanie portów (otwiera się w nowym oknie)
- Docker: dokumentacja pliku Compose (otwiera się w nowym oknie)
- Docker Hub: wordpress (otwiera się w nowym oknie)
- Docker Hub: mariadb (otwiera się w nowym oknie)