SSD Nodes Learn Hosting plans →
Przewodniki Matt ConnorAutor: Matt Connor · Zaktualizowano 2026-08-28

wg-easy konfiguracja WireGuard w Dockerze

Instrukcja uruchomienia wg-easy z Docker Compose. Dowiedz się, jak poprawnie skonfigurować uprawnienia NET_ADMIN, sysctls oraz porty UDP, aby uniknąć błędów w wersji 15.

Co budujesz

wg-easy to WireGuard z interfejsem WWW, działający jako pojedynczy kontener Docker. Narzędzie zarządza interfejsem WireGuard i dodaje interfejs przeglądarkowy do tworzenia klientów. Każdy utworzony klient otrzymuje plik konfiguracyjny oraz kod QR, dzięki czemu telefon łączy się z VPN po skierowaniu aparatu na ekran.

Sam tunel to standardowy WireGuard. Moduł jądra przesyła pakiety, więc przepustowość jest taka sama, jak w przypadku ręcznej konfiguracji. Zyskujesz zarządzanie cyklem życia klienta: dodawanie, wyłączanie i usuwanie peerów bez konieczności edycji pliku konfiguracyjnego przez SSH. Ceną jest brak bezpośredniej kontroli nad tą konfiguracją, co jest przedmiotem ręcznej konfiguracji WireGuard na VPS.

Wymagany jest VPS typu KVM z publicznym adresem IPv4, Docker Engine z wtyczką Compose oraz dostęp root. Wirtualizacja kontenerowa współdzieląca jądro hosta, taka jak OpenVZ lub LXC, zazwyczaj nie pozwala na załadowanie modułu WireGuard, co spowoduje błąd przy próbie uruchomienia interfejsu przez kontener.

Wersja 15 przeniosła ustawienia poza zmienne środowiskowe

Większość dostępnych poradników została napisana dla wg-easy 14, gdzie WG_HOST ustawiało się na adres serwera, a PASSWORD_HASH na skrót bcrypt hasła administratora, oba jako zmienne środowiskowe. Wersja 15 to całkowita przebudowa. Oficjalne notatki migracyjne jasno wskazują, że v15 nie korzysta z tych samych zmiennych środowiskowych co v14, a większość z nich została przeniesiona do panelu administratora w interfejsie webowym.

Zatem WG_HOST oraz PASSWORD_HASH nie pełnią już żadnej funkcji. W przypadku użycia starego pliku compose, kontener uruchomi się, zignoruje te linie, a następnie wyświetli monit o utworzenie konta administratora w przeglądarce. Nie jest to błąd. To nowy proces konfiguracji.

Na lipiec 2026 głównym tagiem, do którego należy przypiąć wersję, jest 15. Należy przypinać główną wersję zamiast używać latest, ponieważ aktualizacja głównej wersji zmienia format konfiguracji na dysku i nie pozwala na łatwe wycofanie zmian.

Plik compose

Utwórz katalog dla stosu i zapisz w nim oficjalny plik compose. Jest to oryginalny plik od dostawcy, bez żadnych modyfikacji.

sudo mkdir -p /etc/docker/containers/wg-easy
sudo curl -o /etc/docker/containers/wg-easy/docker-compose.yml \
  https://raw.githubusercontent.com/wg-easy/wg-easy/master/docker-compose.yml

Zawartość pliku wygląda następująco:

volumes:
  etc_wireguard:

services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:15
    container_name: wg-easy
    networks:
      wg:
        ipv4_address: 10.42.42.42
        ipv6_address: fdcc:ad94:bacf:61a3::2a
    volumes:
      - etc_wireguard:/etc/wireguard
      - /lib/modules:/lib/modules:ro
    ports:
      - "51820:51820/udp"
      - "51821:51821/tcp"
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv6.conf.all.disable_ipv6=0
      - net.ipv6.conf.all.forwarding=1
      - net.ipv6.conf.default.forwarding=1

networks:
  wg:
    driver: bridge
    enable_ipv6: true
    ipam:
      driver: default
      config:
        - subnet: 10.42.42.0/24
        - subnet: fdcc:ad94:bacf:61a3::/64

etc_wireguard to wolumen nazwany, przechowujący klucz serwera oraz wszystkich utworzonych klientów. Wykonuj kopię zapasową tego wolumenu, w przeciwnym razie przebudowa spowoduje utratę wszystkich parów. Jeśli wolisz przechowywać te pliki w systemie plików hosta, zamień go na bind mount. Przed wykonaniem tej operacji zapoznaj się z różnicami między bind mounts a wolumenami nazwanymi, ponieważ uprawnienia działają w obu przypadkach inaczej.

Dlaczego wymagane są NET_ADMIN, SYS_MODULE oraz sysctl

Domyślnie kontener nie ma uprawnień do modyfikacji stosu sieciowego, a każda z tych linii znosi konkretne ograniczenie.

NET_ADMIN pozwala kontenerowi utworzyć interfejs wg0, przypisać mu adres oraz zdefiniować trasy. Bez tego kontener uruchamia się, a następnie kończy działanie podczas inicjalizacji interfejsu, ponieważ ip link add wg0 type wireguard zwraca Operation not permitted.

SYS_MODULE wraz z montowaniem /lib/modules w trybie tylko do odczytu umożliwia kontenerowi załadowanie modułu jądra WireGuard, jeśli nie został on wcześniej załadowany na hoście. Moduł znajduje się w jądrze hosta, a nie wewnątrz obrazu, dlatego katalog hosta musi być widoczny. W nowoczesnych jądrach moduł jest zazwyczaj wbudowany, co można potwierdzić za pomocą sudo modprobe wireguard && echo ok na hoście.

net.ipv4.ip_forward=1 sprawia, że jądro przekazuje pakiety, które nie są zaadresowane bezpośrednio do danej maszyny. Bez tego klient nawiązuje połączenie, uzgadnianie przebiega pomyślnie, a następnie każdy pakiet kierowany do Internetu jest odrzucany, co powoduje przekroczenie czasu oczekiwania ping 1.1.1.1, mimo że VPN wydaje się połączony.

net.ipv4.conf.all.src_valid_mark=1 jest ustawieniem, które często zaskakuje użytkowników. WireGuard oznacza własne pakiety wychodzące, aby nie były one kierowane z powrotem do tunelu. Ścisłe filtrowanie ścieżki zwrotnej (reverse path filtering) wykrywa pakiet, którego adres źródłowy nie pasuje do oczekiwanej trasy i odrzuca go. Ten sysctl instruuje jądro, aby akceptowało oznaczone pakiety, co zapobiega samoczynnemu zrywaniu pełnego tunelu.

Uruchomienie usługi i utworzenie konta administratora

cd /etc/docker/containers/wg-easy
sudo docker compose up -d
sudo docker compose logs -f

Należy używać docker compose up oraz docker compose down, a nie start i stop. Twórcy oprogramowania ostrzegają, że start w kontenerze utworzonym przy innych ustawieniach pozostawia sieć w niespójnym stanie. Jeśli stos ma powrócić po restarcie systemu, restart: unless-stopped już to zapewnia, a zachowanie usług compose podczas startu systemu wyjaśnia, co ta polityka gwarantuje, a czego nie.

Interfejs webowy nasłuchuje na porcie TCP 51821. Przy pierwszej wizycie wyświetlana jest strona konfiguracji, na której tworzy się konto administratora i potwierdza adres hosta, którego klienci będą używać do połączenia z serwerem. Ten adres hosta trafia do linii Endpoint w każdej konfiguracji klienta, więc musi to być publiczny adres IP lub nazwa DNS serwera VPS. Jeśli jest błędny, kod QR przekazany do urządzenia mobilnego wskazuje na nieosiągalny punkt, przez co uzgadnianie połączenia nigdy nie zostanie zakończone.

Jeszcze jedna uwaga dotycząca tego portu: wg-easy 15 odrzuca zwykłe połączenia HTTP, chyba że ustawiona zostanie zmienna INSECURE=true. Dostęp przez HTTPS z niezaufanym certyfikatem lub terminacja TLS na reverse proxy przed usługą są dopuszczalne. Dostęp przez http:// przy ustawieniach domyślnych nie jest możliwy.

Nie udostępniaj portu interfejsu użytkownika w Internecie

Plik compose publikuje port 51821 na wszystkich interfejsach. Jest to strona logowania do urządzenia, które może kierować ruchem sieciowym, dlatego nie powinna być dostępna publicznie. Publikacja portu w Dockerze powoduje dodanie reguł do łańcucha DOCKER, który jest przetwarzany przed ufw, więc reguła blokująca w ufw nie zamknie tego portu. Warto zrozumieć ten mechanizm, a artykuł dlaczego publikowane porty Dockera ignorują ufw szczegółowo go wyjaśnia.

Najprostszym rozwiązaniem jest powiązanie interfejsu użytkownika z adresem loopback i uzyskanie do niego dostępu przez tunel SSH:

    ports:
      - "51820:51820/udp"
      - "127.0.0.1:51821:51821/tcp"
    environment:
      - INSECURE=true

Następnie z poziomu laptopa:

ssh -L 51821:127.0.0.1:51821 youruser@your.server.address

Otwórz http://127.0.0.1:51821 w przeglądarce na swoim laptopie. Ruch jest szyfrowany przez SSH, port nie odpowiada nikomu innemu, a INSECURE=true jest tutaj bezpieczne, ponieważ niezaszyfrowany ruch HTTP nigdy nie opuszcza interfejsu loopback.

Otwarcie portu UDP 51820 i weryfikacja obu firewalli

WireGuard wymaga, aby port UDP 51820 był dostępny z Internetu. Docker publikuje ten port, jednak wielu dostawców stosuje zewnętrzny firewall sieciowy przed serwerem VPS, o którym Docker nie posiada informacji. Port należy otworzyć w obu miejscach. Jeśli zarządzasz firewallem hosta za pomocą ufw, podstawowe reguły ufw dla VPS stanowią szybsze rozwiązanie niż ręczne tworzenie reguł nftables.

Sprawdź, czy kontener faktycznie nasłuchuje:

sudo ss -ulnp | grep 51820

Powinieneś zobaczyć nasłuchujący gniazdo UDP. Brak danych w tej linii oznacza, że kontener nie uruchomił interfejsu, a sudo docker compose logs wg-easy wskaże przyczynę tego stanu.

Tworzenie klienta i skanowanie na telefonie

W interfejsie użytkownika utwórz klienta i nadaj mu nazwę, którą łatwo rozpoznasz, na przykład nazwę urządzenia, do którego należy. wg-easy przydziela kolejny wolny adres tunelu i generuje parę kluczy. Każdy wiersz klienta oferuje kod QR oraz plik .conf do pobrania.

Zainstaluj oficjalną aplikację WireGuard na telefonie, wybierz opcję dodania tunelu z kodu QR i skieruj aparat na kod wyświetlony na ekranie. Tunel pojawi się pod wpisaną nazwą. Włącz go, a wiersz klienta w interfejsie zacznie wyświetlać liczniki transferu oraz czas ostatniego uzgodnienia (handshake). Gdy telefon znajduje się w tunelu, uzyskuje dostęp do usług, które nie zostały opublikowane w Internecie. Dzięki temu telefon może przesyłać zdjęcia do własnego serwera zdjęć z dowolnego miejsca, bez konieczności otwierania choćby jednego portu tego serwera na świat. Ta sama metoda sprawdza się w przypadku multimediów, a biblioteka Jellyfin przekształcona w wypożyczalnię wideo z lat 90. jest wygodna w przeglądaniu z pokoju hotelowego, zachowując przy tym prywatność typową dla sieci lokalnej (LAN). Powiadomienia działają w drugą stronę w ramach tego samego tunelu, ponieważ własny serwer ntfy może wysłać wiadomość na telefon w momencie niepowodzenia zadania kopii zapasowej, nie odpowiadając przy tym na żadne żądania z publicznego Internetu.

Jeśli po włączeniu klienta nie widać uzgodnienia (handshake), oznacza to, że klient w ogóle nie łączy się z serwerem. Wskazuje to na problem z portem UDP 51820, albo na firewallu dostawcy, albo w adresie punktu końcowego zapisanym w konfiguracji. Jeśli uzgodnienie przebiega pomyślnie, ale brak dostępu do Internetu, problem leży po stronie przekierowania ruchu lub konfiguracji DNS.

Na komputerze stacjonarnym pobierz plik .conf i zaimportuj go do klienta WireGuard, zamiast przepisywać dane ręcznie. Klucz prywatny w tym pliku jest generowany i wyświetlany tylko raz. Traktuj ten plik tak samo, jak traktujesz klucz prywatny SSH.

Kiedy zrezygnować z interfejsu graficznego

Narzędzie wg-easy jest odpowiednie, dopóki użytkownikami są ludzie i ich telefony. Interfejs graficzny jest szybszy niż edycja plików konfiguracyjnych, a unieważnienie dostępu dla zgubionego telefonu wymaga jednego kliknięcia.

Ograniczenia tego rozwiązania pojawiają się w momencie potrzeby konfiguracji, której interfejs nie obsługuje. Pierwszą barierą jest zazwyczaj routing typu site-to-site, gdzie AllowedIPs partnera obejmuje całą zdalną podsieć, a nie tylko pojedynczy adres. Kolejnym etapem są tunele dzielone (split tunnels) z regułami routingu dla poszczególnych partnerów lub konfiguracja generowana przez narzędzia do automatyzacji. W tym punkcie ręczna konfiguracja nie jest trudniejsza, jest po prostu inna, a podstawowy przewodnik WireGuard pokazuje ten sam tunel zbudowany przy użyciu wg0.conf. Jeśli wolisz całkowicie zrezygnować z utrzymywania płaszczyzny sterowania, porównanie WireGuard z Tailscale omawia opcję zarządzaną. To, czy jest to opłacalna wymiana, zależy od tego, do czego serwer koordynujący ma dostęp, dlatego przed powierzeniem mu swojej sieci warto zapoznać się z dokumentem model zaufania Tailscale. Kolejną kwestią są zazwyczaj koszty, a zakres darmowego planu Tailscale jest wystarczający, aby gospodarstwo domowe lub mały zespół nie ponosiły żadnych opłat. Powyżej tego poziomu rozliczenia opierają się na liczbie użytkowników, a nie urządzeń, co stanowi inny model kosztów niż w przypadku posiadanego już serwera VPS, dlatego przed migracją zespołu należy sprawdzić koszty Tailscale po przekroczeniu darmowego planu. Pełny tunel, który właśnie zbudowano, ma tam swój bezpośredni odpowiednik, ponieważ ogłoszenie serwera VPS jako węzła wyjściowego Tailscale pozwala uzyskać tę samą trasę wyjściową przez serwer, zatwierdzaną w konsoli administracyjnej zamiast wpisywania jej do konfiguracji każdego klienta. Bariera podsieci również ma swój odpowiednik, ponieważ ogłoszenie całej sieci prywatnej z poziomu VPS udostępnia tę sieć każdemu urządzeniu w sieci tailnet bez konieczności edycji AllowedIPs dla każdego partnera, co wcześniej wymusiło rezygnację z interfejsu graficznego. Jeśli wymagasz panelu sterowania i automatycznego routingu typu mesh, ale nie chcesz korzystać z zewnętrznego serwera koordynującego, uruchomienie własnego serwera NetBird na VPS pozwala zachować kontrolę nad płaszczyzną sterowania na własnym sprzęcie, kosztem konieczności konfiguracji DNS i TLS, których wg-easy nie wymagało.

Jeśli niezrozumiała była składnia compose, a nie sam WireGuard, podstawy Docker Compose na VPS wyjaśniają format pliku oraz codzienne polecenia.

FAQ

Dlaczego wg-easy ignoruje moje zmienne WG_HOST oraz PASSWORD_HASH?

Te zmienne należą do wersji 14 wg-easy. Wersja 15 to całkowite przepisanie kodu, a autorzy przenieśli niemal całą konfigurację do panelu administracyjnego w interfejsie WWW. Kontener nie odczytuje tych zmiennych, więc uruchamia się standardowo i przy pierwszej wizycie prosi o utworzenie konta administratora. Adres hosta widoczny dla klientów należy ustawić na stronie konfiguracji po pierwszym uruchomieniu.

Czy potrzebuję SYS_MODULE, jeśli mój kernel ma już wsparcie dla WireGuard?

Nie. SYS_MODULE oraz montowanie /lib/modules służą do tego, aby kontener mógł załadować moduł, gdy host go nie posiada. Na hoście, gdzie polecenie sudo modprobe wireguard kończy się powodzeniem, ta uprawnienie jest zbędne. Usunięcie go jest zalecanym krokiem w celu zwiększenia bezpieczeństwa, natomiast NET_ADMIN jest wymagane w każdym przypadku.

Klient łączy się, ale brak dostępu do Internetu. Co jest nie tak?

Nawiązany handshake przy braku ruchu niemal zawsze oznacza problem z przekazywaniem pakietów (forwarding). Upewnij się, że net.ipv4.ip_forward=1 oraz net.ipv4.conf.all.src_valid_mark=1 nadal znajdują się w pliku compose, ponieważ ręczna edycja często prowadzi do ich usunięcia. Jeśli forwarding jest włączony, sprawdź serwer DNS, który otrzymał klient. Tunel przesyłający cały ruch przez VPN, który wskazuje na nieosiągalny serwer DNS, zachowuje się w przeglądarce jak zerwane połączenie.

Jak wykonać kopię zapasową klientów?

Wszystkie dane znajdują się w wolumenie nazwanym etc_wireguard, w pliku wg0.json. Interfejs WWW posiada również przycisk kopii zapasowej, który eksportuje te same dane. Przed każdą aktualizacją skopiuj ten plik poza serwer. Przywracanie danych polega na wgraniu pliku podczas etapu konfiguracji nowego kontenera.

Czy mogę uruchomić wg-easy za reverse proxy?

Tak. Umieść proxy przed portem TCP 51821, wykonaj tam terminację TLS i ustaw INSECURE=true w kontenerze, aby akceptował zwykły ruch HTTP z proxy. Port UDP 51820 musi pozostać wystawiony bezpośrednio, ponieważ ruch VPN odbywa się przez UDP i nie przechodzi przez proxy HTTP.