Kör en Redis-server med Podman utan root

Redis 8.10 på Debian 13 i rootless Podman under en egen användare, med JSON och sökning inbyggt, en inloggning per app, anpassad för 8 GB, nåbar bara från servern och via WireGuard, och nattliga ögonblicksbilder du har återställt.

Testad på Redis Open Source 8.10.2 på Debian 13 (trixie) på en server hos Melonslab Uppdaterad 14 oktober 2026

Rekommenderad server för guiden

SSD RAID 1 · ECC DDR4 · 10 Gbit

VC-P Alloy · 2 vCPU · 8 GB Minne · 60 GB Lagring

Månadsvis, ingen bindningstid 7 dagars öppet köp

100 kr/mån

Beställ nu
På den här sidan

Det här sätter du upp

Redis är en nyckel-värde-databas som håller allt i minnet: appar använder den som cache, för sessioner, jobbköer, räknare och gränser för antal anrop. Den svarar på långt under en millisekund eftersom allt ligger i minnet, och den sparar till disk så att datan finns kvar efter en omstart. Sedan Redis 8 har den officiella avbilden också JSON-dokument, en sök- och frågemotor, tidsserier, Bloom-filter och vektormängder inbyggt.

Redis skapades av Salvatore Sanfilippo 2009 och utvecklas av Redis Ltd., ett bolag i USA. Licensen har ändrats två gånger. Till och med 7.2 var Redis öppen källkod under BSD-licensen. Redis 7.4 bytte 2024 till två licenser som inte är öppen källkod, RSALv2 och SSPLv1, och det var då Valkey forkades från 7.2. Sedan Redis 8.0, 2025, kan du också välja AGPLv3, en licens för öppen källkod. Enligt AGPLv3 måste du dela med dig av dina ändringar om du ändrar i Redis egen kod och låter andra använda den över nätverket. Att köra Redis oförändrad för dina egna appar, som här, kräver ingenting av dig. Vill du ha en tillåtande licens använder du Valkey i stället: appar som fungerar med den ena fungerar med den andra.

Redis kontaktar ingen tjänst på internet: när vi avlyssnade testserverns trafik medan Redis startade och betjänade en app var den enda utgående trafiken serverns egen tidssynkronisering.

Här körs Redis från den officiella avbilden, i Podman under en egen användare som heter redis, med en inloggning för varje app och den inbyggda användaren default avstängd. Den lyssnar bara på servern själv och på dess WireGuard-adress, aldrig på den publika adressen.

Varje steg nedan har körts på en nyinstallerad Melonslab VC-P Alloy (2 vCPU, 8 GB) med Debian 13:

  • Redis 8.10.2 startade med sina användare från en hemlighet i Podman, och med modulerna för JSON, sökning, tidsserier och Bloom inlästa. En anslutning utan användarnamn fick NOAUTH Authentication required., och användaren default nekades.
  • Appens inloggning kunde läsa och skriva, spara ett JSON-dokument och hitta det med ett sökindex, men inte köra CONFIG, SHUTDOWN eller ACL. En andra apps inloggning, begränsad till nycklar som börjar med shop:, fick NOPERM på den första appens nycklar.
  • En appserver på WireGuard anslöt med redis-cli och ett Python-skript, och vår dator genom en SSH-tunnel. Från internet fick port 6379 på den publika adressen inget svar.
  • Med 1 GB testdata mätte vi vad varje sätt att spara kostar, och kontrollerade att maxmemory nekar skrivningar, eller kastar ut gamla nycklar, när minnet är fullt.
  • Efter en omstart av servern fanns alla 10 000 testposter kvar. En nattlig ögonblicksbild återställdes till en tom volym, och en uppdatering från 8.8 till 8.10 behöll datan.

Efter en omstart använde hela servern omkring 470 MB minne, varav Redis 11 MB med våra 10 000 poster. Redis växer med din data, upp till gränsen på 4 GB som ställs in i steg 3.

Innan du börjar

Du behöver:

Du behöver inget DNS-namn: apparna ansluter till en IP-adress som bara de kan nå.

Exemplen använder 203.0.113.10 för serverns publika adress, 10.8.0.1 för dess WireGuard-adress, 10.8.0.2 för en appserver på WireGuard och app för appens inloggning. Byt ut dem genomgående.

1. Förbered servern

Som root skapar du /etc/sysctl.d/60-redis.conf:

# Let Redis save snapshots without failing when memory is tight
vm.overcommit_memory = 1
# Let Redis listen on the WireGuard address before the tunnel is up
net.ipv4.ip_nonlocal_bind = 1
sysctl --system
  • För att spara till disk kopierar Redis sig själv i minnet med fork. Linux standardinställning kan neka den kopian när minnet ser ut att ta slut, och då misslyckas sparningen. Rediss dokumentation kräver 1, och utan den skriver Redis WARNING Memory overcommit must be enabled! i loggen vid varje start.
  • Vid uppstart får containern inte vänta in WireGuard, och Podman kan inte lyssna på 10.8.0.1 innan adressen finns. Den andra raden tillåter det, och anslutningar fungerar så snart tunneln är uppe. Utan den startar inte Redis om den hinner före WireGuard (se Felsökning).

Skapa sedan användaren:

useradd -m -s /bin/bash redis
loginctl enable-linger redis
machinectl shell redis@

Allt fram till steg 6 körs som redis.

2. Skapa inloggningarna

Rediss inbyggda användare default har inget lösenord och får köra alla kommandon. Stäng av den och ge varje app en egen inloggning. Redis läser dem från en ACL-fil, som du lagrar som en hemlighet i Podman, så att inget lösenord hamnar i en egen fil:

admin=$(openssl rand -hex 32)
app=$(openssl rand -hex 32)
printf %s "$admin" | podman secret create redis-admin-password -
printf '%s\n' 'user default off' "user admin on >$admin ~* &* +@all" "user app on >$app ~* &* +@all -@admin" | podman secret create redis-users -
unset admin app

Det ger tre användare:

  • default är avstängd, så ingen kan använda Redis utan användarnamn och lösenord.
  • admin får göra allt. Den använder du för säkerhetskopior och ändringar, från servern själv.
  • app får använda alla nycklar (~*) och alla kanaler (&*), och alla kommandon utom de i gruppen @admin: CONFIG, ACL, SHUTDOWN, SAVE, MONITOR, DEBUG, replikering och liknande. Kommandon som KEYS, INFO och FLUSHDB är fortfarande tillåtna, eftersom många appar och bibliotek använder dem, och det är även kommandona för JSON och sökning.

Adminlösenordet lagras också för sig, så att redis-cli i containern kan logga in som admin utan att du skriver det. För att se lösenorden, till appens inställningar:

podman secret inspect --showsecret --format '{{.SecretData}}' redis-users

Lösenordet står efter >. Redis håller bara en SHA-256-hash av det i minnet.

3. Ställ in minne och lagring

Skapa ~/redis.conf:

# Users and passwords come from the redis-users secret
aclfile /run/secrets/redis-users

# Memory: at most 4 GB of data, and refuse writes when it is full
maxmemory 4gb
maxmemory-policy noeviction

# Persistence: a log of every write, flushed to disk every second,
# and a snapshot every hour, or sooner after many changes
appendonly yes
appendfsync everysec
save 3600 1 300 100 60 10000
dir /data

Minne. Redis håller all sin data i minnet, och utan en gräns tar den vad den behöver tills Linux stoppar den. Varje gång den sparar delar kopian den gör med fork minne med Redis, men varje nyckel som ändras medan sparningen pågår tar minne två gånger. I vårt test med 1 GB data kopierade en omskrivning av AOF-filen under tung skrivning 774 MB, det mesta, medan en ögonblicksbild på en lugn server kopierade 2 MB. Håll därför lika mycket minne ledigt som Redis får använda: på en server med 8 GB blir det 4 GB för Redis. Kör andra appar på samma server sänker du gränsen.

När minnet är fullt avgör maxmemory-policy:

  • noeviction, som används här, nekar skrivningar med OOM command not allowed when used memory > 'maxmemory' och behåller allt. Använd den när Redis har sessioner, köer eller annat som din app inte får förlora.
  • allkeys-lru tar bort de nycklar som använts minst nyligen för att få plats. Använd den när Redis bara är en cache, där en saknad nyckel hämtas på nytt. Vi såg den kasta ut gamla nycklar och ta emot den nya vid gränsen.
  • volatile-lru tar bara bort nycklar som har en utgångstid, för en blandning av de två.

Lagring. Redis har två sätt att spara, och den här konfigurationen använder båda:

  • Ögonblicksbilder (RDB): hela datamängden skriven till en kompakt fil, här varje timme om något har ändrats, var 5:e minut efter 100 ändringar och varje minut efter 10 000. Efter en krasch förlorar du det som ändrats sedan den senaste ögonblicksbilden. Vår ögonblicksbild på 1 GB tog 22 till 28 sekunder att skriva och blev en fil på 990 MB. Det är dem säkerhetskopian i steg 8 kopierar.
  • Loggfilen (AOF): varje skrivning läggs också till i en logg, som appendfsync everysec skriver till disk en gång i sekunden. Efter en krasch förlorar du som mest ungefär en sekund. Loggen växer tills Redis skriver om den som en ögonblicksbild plus nya skrivningar, av sig själv när den har fördubblats. Under vår tunga skrivning växte AOF-katalogen till 2,5 GB för 1 GB data före omskrivningen, så lämna plats på disken.

Vi mätte kostnaden med redis-benchmark, 50 klienter som skriver värden på 100 byte:

LagringSkrivningar per sekund
Bara ögonblicksbilder49 400
AOF, everysec48 800
AOF, always9 800

Med everysec såg vi ingen skillnad värd att räkna. appendfsync always väntar på disken vid varje skrivning och förlorar ingenting, med en femtedel av farten. För en ren cache som kan byggas upp igen sparar appendonly no in skrivningarna till disk. En omstart tar längre tid med mer data: Redis svarar LOADING Redis is loading the dataset in memory tills den har läst in allt. För vår 1 GB små nycklar, 8,6 miljoner stycken, tog det 19 sekunder direkt efter att loggfilen hade skrivits om, och 26 sekunder när den innehöll många skrivningar sedan dess.

4. Definiera containern

mkdir -p ~/.config/containers/systemd

Skapa ~/.config/containers/systemd/redis.container:

[Unit]
Description=Redis

[Container]
ContainerName=redis
Image=docker.io/library/redis:8.10
Exec=redis-server /etc/redis/redis.conf
Volume=%h/redis.conf:/etc/redis/redis.conf:ro
Volume=redis-data:/data
Secret=redis-users
Secret=redis-admin-password,type=env,target=REDISCLI_AUTH
# Only this server and WireGuard devices can reach Redis: the port is not open to the internet.
PublishPort=127.0.0.1:6379:6379
PublishPort=10.8.0.1:6379:6379
AutoUpdate=registry

[Service]
Restart=always

[Install]
WantedBy=default.target
  • docker.io/library/redis är den officiella avbilden på Docker Hub. Den läser in modulerna för JSON, sökning, tidsserier och Bloom av sig själv; podman exec redis redis-cli --user admin module list listar dem.
  • Secret=redis-users lägger ACL-filen på /run/secrets/redis-users i containern, där redis.conf läser den.
  • REDISCLI_AUTH är variabeln som redis-cli hämtar sitt lösenord från.
  • De två raderna PublishPort avgör vem som kan ansluta: servern själv på 127.0.0.1 och enheter på WireGuard på 10.8.0.1. Redis lyssnar inte alls på den publika adressen. Utan WireGuard tar du bort den andra raden.
  • Taggen 8.10 ger alla fel- och säkerhetsrättningar i Redis 8.10, och inget mer. Steg 9 har detaljerna.

Starta den:

systemctl --user daemon-reload
systemctl --user start redis
systemctl --user enable --now podman-auto-update.timer
podman exec redis redis-cli --user admin ping

Den svarar PONG. Utan användarnamn får du användaren default, som är avstängd:

podman exec redis redis-cli ping
AUTH failed: WRONGPASS invalid username-password pair or user is disabled.
NOAUTH Authentication required.

5. Släpp in dina appar

Via WireGuard. Gå tillbaka till root med exit och öppna port 6379 bara i tunneln:

ufw allow in on wg0 to any port 6379 proto tcp

På appservern, som har tunneladressen 10.8.0.2, finns redis-cli i Debians paket redis-tools:

apt install -y redis-tools
redis-cli -h 10.8.0.1 --user app --askpass

--askpass frågar efter lösenordet, så att det inte blir kvar i skalets historik. Sedan:

10.8.0.1:6379> set greeting hello
OK
10.8.0.1:6379> get greeting
"hello"
10.8.0.1:6379> json.set doc:1 $ '{"name":"Anna","city":"Malmö"}'
OK
10.8.0.1:6379> config get maxmemory
(error) NOPERM User app has no permissions to run the 'config|get' command

I en app är anslutningsadressen redis://app:PASSWORD@10.8.0.1:6379/0. Trafiken krypteras av WireGuard.

Appar i containrar på den här servern. Inne i en container är 127.0.0.1 containern själv. Använd 10.8.0.1 i stället: serverns WireGuard-adress går att nå från rootless-containrar, vilket vi kontrollerade från en container på samma server.

Från din egen dator, genom SSH. En SSH-tunnel kräver ingen ändring på servern:

ssh -N -L 6380:localhost:6379 root@203.0.113.10

Medan den körs ansluter du i en annan terminal till port 6380 på din egen dator:

redis-cli -p 6380 --user app --askpass

Port 6380 används för att inte krocka med en Redis på din egen dator.

Om TLS. Redis kan kryptera anslutningar själv, med tls-port och ett certifikat. Den här guiden använder det inte: WireGuard och SSH krypterar redan allt som lämnar servern, och anslutningar på 127.0.0.1 lämnar den aldrig. Öppna inte port 6379 mot internet i stället, varken med eller utan TLS.

6. Kontrollera vad andra ser

På servern, som root:

ss -tlnp | grep 6379
LISTEN 0      128          10.8.0.1:6379      0.0.0.0:*    users:(("pasta.avx2",pid=1158,fd=7))
LISTEN 0      128         127.0.0.1:6379      0.0.0.0:*    users:(("pasta.avx2",pid=1158,fd=6))

pasta är programmet som skickar vidare anslutningar in i containern. Bara de två adresserna: inget på 0.0.0.0, [::] eller den publika adressen. Från en dator som inte är med i VPN:et:

nc -zv -w 10 203.0.113.10 6379
nc: connect to 203.0.113.10 port 6379 (tcp) timed out: Operation now in progress

ufw släpper försöket utan att svara, och på servern visar journalctl -k | grep 'DPT=6379' det som [UFW BLOCK]. Redis lyssnar inte heller där, så porten är stängd även om brandväggen skulle vara avslagen.

7. Anslut från en app

Ett exempel i Python, med redis-py, klienten som Redis själva underhåller. På appservern:

python3 -m venv ~/venv
~/venv/bin/pip install redis

Skapa app.py:

import os
import redis

r = redis.Redis(
    host=os.environ.get("REDIS_HOST", "10.8.0.1"),
    port=6379,
    username="app",
    password=os.environ["REDIS_PASSWORD"],
    decode_responses=True,
)

r.set("greeting", "Hello from the app")
print(r.get("greeting"))

# A counter, and a list used as a simple queue
print("visits:", r.incr("visits"))
r.lpush("jobs", "send-invoice:1042")
print("next job:", r.rpop("jobs"))
read -rs REDIS_PASSWORD && export REDIS_PASSWORD
~/venv/bin/python app.py
Hello from the app
visits: 1
next job: send-invoice:1042

En inloggning för varje app

Ge en andra app en egen inloggning, begränsad till nycklar som börjar med dess eget prefix. Som redis lägger du till en rad i hemligheten och startar om:

{ podman secret inspect --showsecret --format '{{.SecretData}}' redis-users; echo "user shop on >$(openssl rand -hex 32) ~shop:* &shop:* +@all -@admin -flushall -flushdb"; } | podman secret create --replace redis-users -
systemctl --user restart redis

shop kan nu bara läsa och skriva nycklar som shop:cart:1, och GET user:42 får NOPERM No permissions to access a key. -flushall -flushdb behövs här: de två kommandona tömmer hela databasen, oavsett vad nyckelgränserna säger. KEYS och SCAN listar fortfarande namnen på alla nycklar, men inte deras värden. Appar som inte ens får se varandras nyckelnamn behöver en egen Redis.

8. Säkerhetskopiera varje natt

En ögonblicksbild kan tas från den Redis som körs, medan apparna fortsätter att använda den. Skapa ~/redis-backup:

#!/bin/sh
# Save a snapshot of Redis, and keep 14 days of them
set -e
umask 077
mkdir -p ~/backup
podman exec redis redis-cli --user admin --rdb /tmp/backup.rdb
podman cp redis:/tmp/backup.rdb ~/backup/redis-$(date +%F).rdb
podman exec redis rm /tmp/backup.rdb
find ~/backup -name 'redis-*.rdb' -mtime +13 -delete

redis-cli --rdb ber Redis om en ny ögonblicksbild, som en replik skulle göra. Den skrivs först till en fil i containern: skickad direkt till skärmen, med -, fick ögonblicksbilden 40 extra byte på slutet. Kör skriptet varje natt med en egen timer för användaren. Skapa ~/.config/systemd/user/redis-backup.service:

[Unit]
Description=Back up Redis

[Service]
Type=oneshot
ExecStart=%h/redis-backup

Och ~/.config/systemd/user/redis-backup.timer:

[Unit]
Description=Back up Redis every night

[Timer]
OnCalendar=*-*-* 02:30
Persistent=true

[Install]
WantedBy=timers.target
chmod 755 ~/redis-backup
systemctl --user daemon-reload
systemctl --user enable --now redis-backup.timer
systemctl --user start redis-backup.service
ls -l ~/backup
-rw-r--r-- 1 redis redis 646902 Oct 14 02:02 redis-2026-10-14.rdb

Spara också inloggningarna en gång, eftersom en ny server behöver dem och dina appar känner till lösenorden:

podman secret inspect --showsecret --format '{{.SecretData}}' redis-users > ~/backup/users.acl

Kopiera ~/backup till en annan maskin, till exempel med restic, och förvara den säkert: den innehåller all din data och lösenorden.

Testa en återställning. När AOF är påslaget och dess katalog saknas startar Redis tom och struntar i en ögonblicksbild bredvid. Det var precis vad vi såg: en återställning med AOF påslaget kom upp utan nycklar. Stäng därför av AOF vid den första starten och slå på det igen när datan är inläst. Som redis, med ögonblicksbilden i ~/backup:

systemctl --user stop redis
podman volume rm redis-data
podman volume create redis-data
podman run --rm -v redis-data:/data -v ~/backup:/backup:ro docker.io/library/redis:8.10 cp /backup/redis-2026-10-14.rdb /data/dump.rdb
sed -i 's/^appendonly yes/appendonly no/' ~/redis.conf
systemctl --user start redis
podman exec redis redis-cli --user admin dbsize
podman exec redis redis-cli --user admin config set appendonly yes
sed -i 's/^appendonly no/appendonly yes/' ~/redis.conf

dbsize visar hur många nycklar som kom tillbaka: alla våra 10 002. config set appendonly yes skriver en ny AOF-fil från datan i minnet. Vänta tills podman exec redis redis-cli --user admin info persistence | grep aof_rewrite_in_progress visar 0 innan du startar om Redis. På en ny server skapar du redis-users från users.acl i steg 2, med podman secret create redis-users ~/backup/users.acl, och redis-admin-password från adminlösenordet i den.

9. Uppdatera

podman auto-update letar en gång om dagen efter en ny avbild under taggen 8.10 och startar om Redis när det finns en: de mindre versionerna med fel- och säkerhetsrättningar. För att se vad den skulle göra just nu:

podman auto-update --dry-run

En ny delversion, som 8.12, eller en ny huvudversion kräver att du byter tagg. Gör en säkerhetskopia, läs versionsinformationen på GitHub, ändra Image= i redis.container och starta om:

systemctl --user daemon-reload
systemctl --user restart redis
podman exec redis redis-cli --user admin info server | grep redis_version

Vi testade en uppdatering från 8.8.3 till 8.10.2 på det här sättet, och datan följde med, även ett JSON-dokument. Att gå tillbaka till en äldre version fungerar inte säkert, eftersom en nyare Redis kan skriva ögonblicksbilder som en äldre inte kan läsa: det är därför du har säkerhetskopian. Taggarna 8 och latest skulle också flytta dig till varje ny delversion av sig själva, så vi använder 8.10. Kontrollera även licensen före en ny huvudversion: den ändrades med 7.4 och 8.0.

Felsökning

Redis startar inte efter en omstart, och loggen säger Failed to bind port 6379 (Cannot assign requested address) for option '-t 10.8.0.1/6379-6379:6379-6379'. Redis startade före WireGuard, och net.ipv4.ip_nonlocal_bind är inte satt. Kontrollera att sysctl net.ipv4.ip_nonlocal_bind visar 1 (steg 1), och kör sedan systemctl --user reset-failed redis och systemctl --user start redis som redis.

NOAUTH Authentication required. eller WRONGPASS invalid username-password pair or user is disabled. Klienten ansluter utan användarnamn, som default, eller med fel lösenord. Ange användarnamnet app utöver lösenordet.

NOPERM User app has no permissions to run the '...' command. Kommandot ingår i gruppen @admin. Kör det som admin på servern, eller lägg till det på appens rad i hemligheten om appen verkligen behöver det, till exempel +config|get, och starta om.

OOM command not allowed when used memory > 'maxmemory'. Redis är full. Höj maxmemory om servern har minne över, ta bort data, eller använd allkeys-lru om Redis bara är en cache (steg 3).

LOADING Redis is loading the dataset in memory. Redis har just startat och läser fortfarande in sin data från disk. Vänta: det tog 19 till 26 sekunder för 1 GB på vår server.

Datan är borta efter en återställning. AOF var påslaget vid den första starten. Börja om från stegen för återställning, med appendonly no vid den första starten.

En appserver får Connection timed out mot 10.8.0.1. Kontrollera med wg show att WireGuard är uppe i båda ändar, och att ufw har regeln från steg 5.

Kör det på din egen server

SSD RAID 1 · ECC DDR4 · 10 Gbit

VC-P Alloy

100 kr/mån

vCPU
2
Minne
8 GB
Lagring
60 GB
Trafik
10 TB
Performance
SSD · RAID 1
  • Full root-åtkomst
  • Nativt /64 IPv6
  • RAID-skyddad lagring
  • Malmö, Sverige
  • Månadsvis, ingen bindningstid
  • 7 dagars öppet köp
Alla guider