 Autor: [Piotr Wasilewski](/autorzy/piotr-wasilewski) Architekt rozwiązań chmurowych · Zweryfikowano Kwiecień 2026

1.  [Strona główna](/) ›
2.  [Baza wiedzy](/baza-wiedzy/) ›
3.  RabbitMQ — message broker na VPS

# RabbitMQ na VPS — exchanges, queues i PHP consumer

Opublikowano: 10 kwietnia 2026 · Kategoria: VPS

Wysyłka emaili podczas żądania HTTP sprawia że user czeka kilka sekund. Generowanie raportu PDF blokuje PHP na minutę. Importowanie 10 000 rekordów z CSV zajmuje pamięć procesu webowego. Rozwiązaniem jest kolejkowanie zadań przez message broker: aplikacja odkłada zadanie do kolejki i odpowiada natychmiast, a osobny worker przetwarza je asynchronicznie. RabbitMQ to jeden z najpopularniejszych message brokerów — dojrzały, niezawodny, z rozbudowanym management UI. Ten artykuł pokazuje kompletną instalację i integrację z PHP przez bibliotekę amqplib.

## Instalacja RabbitMQ na Ubuntu 22.04 / 24.04

\# Instalacja przez oficjalny skrypt packagecloud
curl -s https://packagecloud.io/install/repositories/rabbitmq/rabbitmq-server/script.deb.sh | sudo bash
curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.deb.sh | sudo bash

sudo apt update
sudo apt install erlang-base erlang-asn1 erlang-crypto erlang-eldap \\
  erlang-ftp erlang-inets erlang-mnesia erlang-os-mon erlang-parsetools \\
  erlang-public-key erlang-runtime-tools erlang-snmp erlang-ssl \\
  erlang-syntax-tools erlang-tftp erlang-tools erlang-xmerl -y

sudo apt install rabbitmq-server -y

# Start i autostart
sudo systemctl enable --now rabbitmq-server
sudo systemctl status rabbitmq-server

# Wlacz management UI (port 15672)
sudo rabbitmq-plugins enable rabbitmq\_management

# Sprawdz wersje
sudo rabbitmqctl status | grep -E "RabbitMQ|Erlang"

## Użytkownicy, vhosty i uprawnienia

\# Domyslny uzytkownik "guest" dziala TYLKO z localhost
# Stworz uzytkownika admina dla management UI
sudo rabbitmqctl add\_user admin StrongPassword123
sudo rabbitmqctl set\_user\_tags admin administrator
sudo rabbitmqctl set\_permissions -p / admin ".\*" ".\*" ".\*"

# Stworz uzytkownika aplikacji z ograniczonymi uprawnieniami
sudo rabbitmqctl add\_user appuser AppPassword456
# Parametry: pattern dla configure, write, read
sudo rabbitmqctl set\_permissions -p / appuser "^app\\." "^app\\." "^app\\."

# Virtual hosty — separacja srodowisk
sudo rabbitmqctl add\_vhost production
sudo rabbitmqctl add\_vhost staging
sudo rabbitmqctl set\_permissions -p production appuser ".\*" ".\*" ".\*"

# Lista uzytkownikow i vhostow
sudo rabbitmqctl list\_users
sudo rabbitmqctl list\_vhosts

## Exchanges — typy i zastosowania

Exchange

Routing

Kiedy używać

**direct**

routing\_key = binding\_key (dokładny match)

Task queues, jeden typ zadania → jedna kolejka

**topic**

Wzorzec z \* (1 słowo) i # (0+)

Multi-tenant routing, filtrowanie po kategoriach

**fanout**

Ignoruje routing\_key, wszystkie queues

Broadcast: inwalidacja cache, notyfikacje push

**headers**

Nagłówki AMQP (x-match: all/any)

Złożone filtrowanie, rzadko używane

**default**

routing\_key = nazwa kolejki

Prostota — bezpośredni publish do queue

\# Tworzenie exchange, queue i binding przez management HTTP API

# Direct exchange dla emaili
curl -u admin:StrongPassword123 -X PUT http://localhost:15672/api/exchanges/%2F/emails \\
  -H "content-type: application/json" \\
  -d '{"type":"direct","durable":true}'

# Utwórz kolejke durable z DLX i TTL
curl -u admin:StrongPassword123 -X PUT http://localhost:15672/api/queues/%2F/email-transactional \\
  -H "content-type: application/json" \\
  -d '{
    "durable": true,
    "arguments": {
      "x-dead-letter-exchange": "emails-dlx",
      "x-message-ttl": 86400000,
      "x-max-length": 100000
    }
  }'

# Binding: exchange "emails" → queue przez klucz "transactional"
curl -u admin:StrongPassword123 -X POST \\
  http://localhost:15672/api/bindings/%2F/e/emails/q/email-transactional \\
  -H "content-type: application/json" \\
  -d '{"routing\_key":"transactional"}'

## PHP AMQP — producent i konsument

Instalacja biblioteki `php-amqplib` przez Composer:

composer require php-amqplib/php-amqplib

<?php
// producer.php — wysyla zadania do kolejki

use PhpAmqpLib\\Connection\\AMQPStreamConnection;
use PhpAmqpLib\\Message\\AMQPMessage;

$connection = new AMQPStreamConnection('localhost', 5672, 'appuser', 'AppPassword456');
$channel = $connection->channel();

// Deklaracja exchange (idempotentna)
$channel->exchange\_declare('emails', 'direct', false, true, false);

$payload = json\_encode(\[
    'to' => 'user@example.com',
    'subject' => 'Potwierdzenie zamowienia #12345',
    'template' => 'order\_confirmation',
    'order\_id' => 12345,
\]);

$message = new AMQPMessage($payload, \[
    'delivery\_mode' => AMQPMessage::DELIVERY\_MODE\_PERSISTENT,   // Zapis na dysk
    'content\_type'  => 'application/json',
\]);

// Publisher Confirms — czekaj na potwierdzenie od brokera
$channel->confirm\_select();
$channel->basic\_publish($message, 'emails', 'transactional');
$channel->wait\_for\_pending\_acks(5.0);

echo "Wiadomosc wyslana\\n";
$channel->close();
$connection->close();

<?php
// consumer.php — worker przetwarzajacy wiadomosci

use PhpAmqpLib\\Connection\\AMQPStreamConnection;
use PhpAmqpLib\\Message\\AMQPMessage;

$connection = new AMQPStreamConnection('localhost', 5672, 'appuser', 'AppPassword456');
$channel = $connection->channel();

// prefetch=1: pobierz jedna wiadomosc na raz (fair dispatch)
$channel->basic\_qos(0, 1, false);

$callback = function (AMQPMessage $msg): void {
    $data = json\_decode($msg->getBody(), true);

    try {
        echo "Przetwarzam email do: {$data\['to'\]}\\n";
        // ... logika wysylki emaila ...

        $msg->ack();   // Potwierdzenie — wiadomosc usunieta z kolejki
        echo "Email wyslany, ACK\\n";
    } catch (\\Exception $e) {
        echo "Blad: {$e->getMessage()}\\n";
        $msg->nack(false);   // NACK, requeue=false → trafi do DLX
    }
};

$channel->basic\_consume('email-transactional', '', false, false, false, false, $callback);

echo "Worker gotowy, czekam na wiadomosci...\\n";
while ($channel->is\_consuming()) {
    $channel->wait();
}

$channel->close();
$connection->close();

## Dead Letter Exchange — obsługa błędów i TTL

\# Utwórz DLX exchange i dead-letter queue

curl -u admin:StrongPassword123 -X PUT http://localhost:15672/api/exchanges/%2F/emails-dlx \\
  -H "content-type: application/json" \\
  -d '{"type":"direct","durable":true}'

curl -u admin:StrongPassword123 -X PUT http://localhost:15672/api/queues/%2F/email-dead-letter \\
  -H "content-type: application/json" \\
  -d '{"durable":true}'

curl -u admin:StrongPassword123 -X POST \\
  http://localhost:15672/api/bindings/%2F/e/emails-dlx/q/email-dead-letter \\
  -H "content-type: application/json" \\
  -d '{"routing\_key":"transactional"}'

# Wiadomosci odrzucone (nack requeue=false) lub po TTL laduja w email-dead-letter

## Monitoring przez CLI i management UI

\# Monitoring kolejek (liczba wiadomosci oczekujacych i niepotwierdzonych)
sudo rabbitmqctl list\_queues name messages messages\_ready messages\_unacknowledged

# Tunel SSH do management UI
ssh -L 15672:localhost:15672 user@vps-ip
# Nastepnie: http://localhost:15672

# Podejrzyj wiadomosc bez usuwania (dla debugowania)
curl -u admin:StrongPassword123 -X POST \\
  http://localhost:15672/api/queues/%2F/email-dead-letter/get \\
  -H "content-type: application/json" \\
  -d '{"count":5,"ackmode":"ack\_requeue\_true","encoding":"auto"}'

# Zuzycie pamieci i dysku
sudo rabbitmq-diagnostics memory\_breakdown

## Klastrowanie — 3 węzły z Quorum Queues

\# Na WSZYSTKICH węzłach — ustaw /etc/hosts
echo "10.0.0.1 rabbit1" | sudo tee -a /etc/hosts
echo "10.0.0.2 rabbit2" | sudo tee -a /etc/hosts
echo "10.0.0.3 rabbit3" | sudo tee -a /etc/hosts

# Skopiuj Erlang cookie z węzła 1 na pozostałe (musi byc identyczny)
sudo cat /var/lib/rabbitmq/.erlang.cookie
# Skopiuj wynik do /var/lib/rabbitmq/.erlang.cookie na rabbit2 i rabbit3
# sudo chmod 400 /var/lib/rabbitmq/.erlang.cookie

# Na rabbit2 i rabbit3 — dolacz do klastra
sudo rabbitmqctl stop\_app
sudo rabbitmqctl reset
sudo rabbitmqctl join\_cluster rabbit@rabbit1
sudo rabbitmqctl start\_app

# Sprawdz status klastra
sudo rabbitmqctl cluster\_status

# Quorum queue (HA z automatyczna replikacja — zalecane zamiast classic mirrored)
curl -u admin:StrongPassword123 -X PUT http://localhost:15672/api/queues/%2F/tasks-ha \\
  -H "content-type: application/json" \\
  -d '{
    "durable": true,
    "arguments": {
      "x-queue-type": "quorum",
      "x-dead-letter-exchange": "emails-dlx"
    }
  }'

## Dobre praktyki

-   **Zawsze używaj durable queues i persistent messages** — inaczej restart RabbitMQ wyczyści wszystkie wiadomości bez ostrzeżenia.
-   **prefetch\_count=1 dla CPU-intensive tasks** — fair dispatch zapobiega sytuacji gdzie jeden worker dostaje 1000 zadań, a pozostałe stoją bezczynnie.
-   **DLX jest obowiązkowy** — bez niego błędnie przetworzone wiadomości giną bezpowrotnie lub zapętlają się w nieskończoność.
-   **Quorum queues zamiast classic mirrored** — od RabbitMQ 3.10+ quorum queues są domyślnie zalecane w klastrach (lepsza spójność danych).
-   **Firewall dla portów AMQP** — port 5672 i management UI (15672) powinny być dostępne tylko z sieci prywatnej lub przez tunel SSH.

## Najczęstsze pytania

Do czego służy RabbitMQ i kiedy go potrzebuję? +

RabbitMQ to message broker — pośrednik między aplikacjami, który buforuje wiadomości i gwarantuje ich dostarczenie. Potrzebujesz go gdy: chcesz asynchronicznie przetwarzać zadania (wysyłka emaili, generowanie raportów), chcesz odsprzęgnąć producenta od konsumenta (producent nie czeka na wynik), chcesz rozdzielić ruch między wiele workerów, albo chcesz zagwarantować że żadna wiadomość nie zostanie zgubiona nawet gdy consumer padnie.

Czym różnią się exchanges w RabbitMQ: direct, topic, fanout? +

Direct exchange routuje wiadomość do kolejki, której binding key = routing key wiadomości. Topic exchange używa wzorców z wildcardami (\* = jedno słowo, # = zero lub więcej słów). Fanout ignoruje routing key i wysyła do WSZYSTKICH przypiętych kolejek — idealny do broadcast (np. inwalidacja cache na wielu serwerach). Headers exchange routuje po nagłówkach AMQP, rzadko używany.

Co to jest Dead Letter Exchange (DLX) w RabbitMQ? +

DLX to exchange, do którego trafiają wiadomości odrzucone (nack/reject), które przekroczyły TTL, albo których kolejka jest pełna. Zamiast gubić te wiadomości, kierujesz je do osobnej kolejki dead-letter skąd można je przeanalizować lub ponownie przetworzyć. Konfiguracja: przy deklaracji kolejki dodaj argument x-dead-letter-exchange. DLX jest niezbędny w systemach produkcyjnych.

Jak RabbitMQ gwarantuje że wiadomość nie zostanie zgubiona? +

Przez trzy mechanizmy: (1) Persistent messages — producent ustawia delivery\_mode=2, wiadomość jest zapisywana na dysk przed potwierdzeniem. (2) Durable queues — kolejka przeżywa restart RabbitMQ. (3) Consumer ACK — consumer musi potwierdzić (basic.ack) po przetworzeniu. Dopiero wtedy wiadomość jest usuwana z kolejki. Jeśli consumer padnie przed ACK, wiadomość wraca do kolejki. Publisher Confirms potwierdzają że wiadomość dotarła do exchange.

## Sprawdź oferty pasujące do tego scenariusza

Poniżej masz szybkie przejścia do ofert i stron z kodami rabatowymi tam, gdzie są dostępne.

Contabo

VPS z dużym RAM — RabbitMQ cluster 3 węzłów wymaga min. 2 GB RAM per node

VPS Cluster

[Aktywuj rabat →](/out/contabo)

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/contabo)

Mikr.us

Tani VPS do testowania RabbitMQ i AMQP w środowisku deweloperskim

Dev/Test

[Aktywuj rabat →](/out/mikrus)

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/mikrus)

CyberFolks

Hosting z kolejkami zadań przez cron — alternatywa dla prostych scenariuszy

Managed

[Aktywuj rabat →](/out/cyberfolks)

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/cyberfolks)

## Powiązane strony

-   [Redis Cluster — sharding i HA](/baza-wiedzy/redis-cluster-konfiguracja)
-   [Memcached vs Redis — porównanie](/baza-wiedzy/memcached-vs-redis-hosting)
-   [Docker na VPS — instalacja i konfiguracja](/baza-wiedzy/docker-na-vps)
-   [Wszystkie artykuły](/baza-wiedzy/)