In short and in plain language
Your server writes every visit to your shop into a log. It also contains the visitor's internet address. That is personal data.
The article explains what data protection says about how long this may be stored. It also shows where such data is kept. For example, in backups.
It is also about how you delete logs or shorten addresses.
We keep the related details in your shop up to date. We match them with the settings of your server.
Every request to a shop leaves a line in the access log: time, requested URL, status code, browser identifier and the visitor's IP address. The web server writes that line without anyone setting it up. Without a format of its own, nginx uses the predefined "combined" format, and its first field is $remote_addr (nginx documentation). Over weeks this builds up a stock of personal data that hardly anyone watches day to day. No statute answers with a number how long it may stay. Germany's Federal Commissioner for Data Protection considers five weeks (BfDI) of storage followed by aggregation sufficient for a monthly report, but in an assessment written for federal public bodies. This article explains what that means for a shop, how security purposes and analysis can be separated, and which maintenance tasks depend on log rotation, truncated addresses, backups and staging copies.
Key takeaways
- Dynamic IP addresses in server logs are personal data: the CJEU ruled so in case C-582/14 of 19 October 2016 (CJEU), provided the operator has legal means to have the person identified with the help of the internet access provider.
- Neither the GDPR nor German law sets a fixed retention period for a shop's server logs. Art. 5(1)(e) GDPR only allows data to be kept in identifiable form for as long as the purpose requires.
- For monthly reports the BfDI considers five weeks (BfDI) of storage followed by aggregation sufficient. It is an assessment for federal bodies and a guide value for shops, not a rule.
- Security and statistics belong in separate logs: the raw log with the full address short and justified, the analysis log with a truncated address until the monthly report, then only counts.
- Debian ships nginx and Apache with daily rotation and 14 (Debian) retained files. That is a package setting, not a justified retention period, and it needs checking and documenting in the record of processing.
- Backed-up logs and logs copied to staging keep their IP addresses for as long as the backup or copy itself. A deletion period only works once backups and test systems follow it too.
What the access log contains
A shop logs in more places than are visible in daily operation. The most familiar one is the web server's access log. In nginx the "combined" format applies unless configured otherwise, and it starts with the address of the requesting machine (nginx documentation). Apache behaves the same way: the %h placeholder writes the IP address as long as name resolution via HostnameLookups is switched off, which according to the documentation is the default (Apache HTTP Server Documentation). Anyone who has not touched the log configuration since installation is therefore storing the full address of every visitor, every search engine robot and every attacker.
That these addresses are personal data is settled. In case C-582/14, still under the GDPR's predecessor directive, the Court of Justice of the European Union held that a dynamic IP address is personal data for a website operator if the operator has legal means to have the person identified with additional information held by the access provider (CJEU). The BfDI concludes that processing log files in general counts as processing personal data (BfDI). Every line in the access log is therefore subject to the GDPR principles of purpose limitation, data minimisation and storage limitation. How the web server itself is protected against attacks is covered in the article on server hardening for shops.
Where IP addresses end up in a shop
Why no law names a number
The GDPR governs storage periods through a principle, not through days. Under Art. 5(1)(e) GDPR, personal data may only be kept in a form that permits identification for as long as necessary for the purposes (GDPR). Recital 39 is more specific: to ensure data is not kept longer than necessary, the controller should establish time limits for erasure or for a periodic review (GDPR). Setting a period is therefore the controller's task. Its length is set by the shop operator, who must be able to justify it.
The legal basis for server logs in a shop is usually Art. 6(1)(f) GDPR, legitimate interest. The German Data Protection Conference describes the assessment in three stages (Datenschutzkonferenz): a legitimate interest, the necessity of the processing to pursue it, and the balancing against the interests of the data subjects in the individual case. For security purposes Recital 49 sets the direction: it names processing to ensure network and information security, for example by operators of communication networks and providers of security services, as a legitimate interest to the extent strictly necessary and proportionate (GDPR). For your own shop that shows the direction but does not replace your own balancing test. In the same case the CJEU accepted that an operator, there federal institutions, may have a legitimate interest in ensuring that its websites keep functioning beyond their specific use (CJEU).
For a monthly evaluation of website visits it is therefore sufficient to store this data for only five weeks and to convert it into the aggregated form of a monthly evaluation.
This sentence is often quoted as a retention period for all logs. It does not support that. The BfDI assesses processing by federal public bodies, bases it on Art. 6(1)(e) GDPR together with the Federal Data Protection Act, and refers to the purpose of "optimising the website" (BfDI). For that purpose the full IP address is usually not necessary, according to the BfDI (BfDI). The page does not name a period in days for attack detection. For a shop the figure is therefore a guide value for analysis, not a rule for the raw log, and the legal basis remains legitimate interest with a balancing test of its own.
| Purpose | What the log needs | Guide value for the period | After the period |
|---|---|---|---|
| Security and attack defence | Full IP address, time, request | Short and justified per shop; the BfDI gives no value in days | Delete |
| Debugging | Request, status, time; the address is mostly unnecessary | Until the error is resolved | Delete or truncate |
| Analysis of visits | Truncated or replaced address | Five weeks (BfDI) for a monthly report | Convert into counts |
| Monthly statistics | No address, only totals | Without personal reference no GDPR deletion duty | Keep |
Two purposes, two logs
Often the problem is not the length of the period but the mixing of purposes. A single access log serves attack defence, debugging and statistics at once, and its retention then follows the longest of those purposes. Defending against an attack needs the full address: it gets blocked, reported or matched against other events. Finding out how many visits a category page had in October does not need it. The German Data Protection Conference explicitly gives counting page views from log files without personal data as an example (Datenschutzkonferenz).
The consequence is a split into two logs. The raw log with the full address stays on the web server or firewall and has a short period justified by the security purpose. The BfDI points out that storing the unchanged IP address away from the web server and firewall systems increases the risk of the processing (BfDI). The analysis log only receives the address truncated or replaced, is kept until the monthly report and then converted into counts. If you do not need your own analysis, leave out the second log. Upstream protection layers log every request themselves, as the article on WAF and bot protection shows, and their logs need a period of their own.
The security period follows detection, not disk space
A seasonal example: investigating failed attempts at the voucher field or suspicious logins during a promotion week needs the addresses of the last few days, not those of the spring. What such patterns look like and which data the investigation needs is shown in the article on discount codes in Black Week. The justification of the period records which cases the raw log is meant to cover, how quickly the operation typically notices them, and why longer retention adds no protection.
Truncate IP addresses effectively
Truncating means discarding the rear part of the address. An IPv4 address is 32 bits (RFC 791) long, and removing the last byte is common. The IpUtils::anonymize helper of the Symfony framework, which Shopware is also built on, removes 1 byte for IPv4 and 8 bytes for IPv6 by default (Symfony). For IPv4 that is a common compromise: the network stays recognisable for analysis, the individual connection no longer does without further effort.
For IPv6 the same rule is not enough. An IPv6 address is 128 bits (RFC 4291) long, and for common addresses the last 64 bits (RFC 4291) form the interface identifier. Removing exactly that part keeps the network prefix, which often belongs to a single connection. The address assignment recommendation provides home sites with significantly more than a single /64 network (RFC 6177). The example configuration below therefore keeps only the first three groups for IPv6. Whether that creates enough distance depends on the assignment practice of access providers; if you need it tighter, keep only two groups and document the decision.
| Address type | Length | Symfony removes by default | What remains |
|---|---|---|---|
| IPv4 | 32 bits (RFC 791) | 1 byte (Symfony) | The first three bytes, i.e. a /24 network |
| IPv6 | 128 bits (RFC 4291) | 8 bytes (Symfony) | The /64 prefix, which often still belongs to one connection (RFC 6177) |
Replacing instead of truncating is the second option. The BfDI names changing the IP address, possibly with a hash function, as a measure that can reduce the risk adequately without impairing the purpose (BfDI). A plain hash of an IPv4 address hardly achieves this, though: with 32 bits the entire address space can be computed and every hash mapped back to its address. Replacement only becomes effective with a secret key that is rotated regularly and destroyed afterwards. Art. 32 GDPR explicitly lists pseudonymisation as a technical measure (GDPR). In nginx, truncation works without an extra module:
# Second access log with a truncated address for analysis (http context).
# IPv4: the last byte becomes 0. IPv6: only the first three groups (48 bits) remain.
# Short forms with "::" inside the first three groups fall back to the default "-".
map $remote_addr $ip_short {
"~^(?<v4>\d+\.\d+\.\d+)\.\d+$" $v4.0;
"~^(?<v6>[0-9a-f]{1,4}:[0-9a-f]{1,4}:[0-9a-f]{1,4}):" $v6::;
default "-";
}
log_format short '$ip_short - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent"';
# Separate directory so the package rule for /var/log/nginx/*.log does not match
access_log /var/log/nginx/analysis/access-short.log short;These lines belong in the http context. If a server block has access_log directives of its own, the outer setting no longer applies there, and the line for the analysis log is added to that block as well. The raw log keeps running unchanged alongside and keeps its short period. Create the directory for the analysis log before reloading. A separate directory is needed because the package rotation rule covers all files matching /var/log/nginx/*.log, and logrotate rejects a file that appears in two rules with an error.
Log rotation: check defaults instead of inheriting them
How long logs actually stay is decided by logrotate on many Linux servers. Packages bring their own defaults for it. Debian ships nginx and Apache with daily rotation and 14 (Debian) retained files, plus the current file. Rules without settings of their own inherit from the global file the weekly rotation and the instruction to keep 4 weeks (Debian) of old logs. A log with no rule at all is not rotated by logrotate in the first place. Both values are package settings. Whether they fit the purpose of a particular shop is usually not checked at installation, and exactly that check is the core of the retention period.
Three settings deserve special attention. rotate defines how often a log is rotated before it is removed; with a value of -1 old logs are not removed at all unless maxage applies (logrotate manual). maxage removes rotated files older than a number of days, but only checks that age when the log is actually rotated (logrotate manual). If a log stays empty and notifempty is set, the old files therefore remain as well. And shred overwrites files before deletion; without the option they are only unlinked (logrotate manual).
# /etc/logrotate.d/nginx-analysis
# Analysis log: five weeks of seven daily files, after that only the monthly report
/var/log/nginx/analysis/access-short.log {
daily
rotate 35
maxage 35
missingok
compress
delaycompress
sharedscripts
postrotate
invoke-rc.d nginx rotate >/dev/null 2>&1
endscript
}Besides logrotate there are places with logic of their own. The system journal does not delete by age unless configured: MaxRetentionSec defaults to 0 (systemd), which turns the feature off, and the documentation explicitly names enforcing data retention policies as a reason to change it. Applications built on Symfony often write their logs through Monolog. Its rotating handler keeps files without limit unless told otherwise; the value 0 means no limit there (Monolog). Whether a shop's application logs contain IP addresses and how many files they keep is defined in that shop's own configuration, and that is where to look.
Include backups and staging copies
The cleanest log rotation ends at the edge of the server. A backup that includes /var/log keeps every log line for as long as the backup itself, so with retention over months, for months. The same applies to staging systems created as a full copy of production and to log excerpts that end up in tickets, chats or emails to service providers. What counts for the retention period is not when the original rotates but when the last copy disappears.
For backups there are two clean options: exclude log directories from the backup if the logs play no role in a restore, or align the backup retention with the shortest period it contains. How deletion duties and backups fit together in general is covered in the article on GDPR-compliant backup retention. For staging systems, logs are skipped or emptied when copying, and the test system gets its own short rotation. How test environments get by without unnecessary real data is shown in the article on staging environments.
- Inventory taken: every place where IP addresses are written, from the web server through firewall and application to journal and mail.
- One purpose and one legal basis recorded per log, raw log and analysis log separated.
- Rotation read per log instead of assumed:
rotate,maxageandnotifemptychecked. - Oldest existing log compared with the documented period, on the server, in the backup and on staging.
- IPv6 truncation checked: does the prefix of a single connection still remain after truncating?
- Access to raw logs restricted to operations; analysis works only with the truncated log.
- Log excerpts in tickets and emails truncated before they go to third parties.
- Period and deletion path updated in the record of processing and in the privacy policy.
Comparing against the oldest existing log is the simplest measurement of whether the period actually applies. The following script reports the oldest access file per directory and its age by modification time; it measures the raw log and the analysis log separately so that the longer period of one does not hide the shorter period of the other. That is the time of the last entry, because logrotate keeps it when compressing; the oldest entry in the file can be up to one rotation interval earlier:
#!/usr/bin/env bash
# Oldest access log per directory and its age in days (by modification time)
# -maxdepth 1 keeps the raw log and the analysis log apart
now=$(date +%s)
for dir in /var/log/nginx /var/log/nginx/analysis /var/log/apache2; do
[ -d "$dir" ] || continue
find "$dir" -maxdepth 1 -type f -name 'access*' -printf '%T@ %p\n' \
| sort -n | head -n 1 \
| awk -v now="$now" '{ printf "%s: %d days\n", $2, (now - $1) / 86400 }'
doneUpdate the record of processing and privacy policy
A retention period only takes effect once it is written down. Under Art. 30(1)(f) GDPR the record of processing activities should, where possible, contain the envisaged time limits for erasure of the different categories of data (GDPR). Under Art. 13(2)(a) GDPR the privacy policy must state the period for which the data will be stored or, if that is not possible, the criteria used to determine it (GDPR). And under Art. 5(2) GDPR the controller must be able to demonstrate compliance with the principles, including storage limitation (GDPR).
The German Data Protection Conference describes a widespread shortcut: blanket statements that processing is lawful under Art. 6(1)(f) GDPR do not meet the legal requirements, yet they are frequently found in privacy policies (Datenschutzkonferenz). For server logs this means that purpose, legitimate interest and period are named specifically, separately for the raw log and the analysis log. If you truncate addresses, say so too, because it is part of the balancing.
The IT-Grundschutz Compendium of Germany's Federal Office for Information Security adds the organisational side. Its module on logging states that log data must be deleted according to a defined process and that uncontrolled deletion or modification must be prevented technically (BSI IT-Grundschutz). In addition, administrators carrying out the work should themselves have no permission to modify or delete recorded logs (BSI IT-Grundschutz). For a shop the Grundschutz is not law, but it is a recognised description of what an orderly deletion path looks like.
Purpose
Security, debugging or analysis, exactly one per log. Otherwise the longest purpose sets the period.
Legal basis
In a shop usually legitimate interest, with a concrete balancing test instead of a blanket sentence.
Period
A justified value that matches the configuration and can be measured on the server.
Truncation
How many bits of the address remain, decided separately for IPv4 and IPv6.
Copies
Backups, staging systems and exports with their own retention.
Access
Who may read raw logs and who only sees the truncated analysis.
Keep the period in the maintenance cycle
Take inventory
Record every place where IP addresses are written: web server, upstream systems, shop system, system journal, mail. Note path, format and rotation for each.
Assign a purpose
Define one purpose per log. Where a log serves several purposes, separate the raw security log from the truncated analysis log.
Set period and truncation
Justify a short period for the raw log from the security purpose. For analysis, the BfDI assessment of five weeks (BfDI) serves as a guide value, after which only counts remain.
Adjust the configuration
Set log format, rotation and deletion so they match the period, including application logs and the system journal.
Include copies
Check backups, staging and exports for logs they contain and align their retention with the period or exclude the logs.
Document and re-measure
Update the record of processing and the privacy policy. In each maintenance cycle compare the oldest existing log with the period, especially after updates and server moves.
Record every place where IP addresses are written: web server, upstream systems, shop system, system journal, mail. Note path, format and rotation for each.
Define one purpose per log. Where a log serves several purposes, separate the raw security log from the truncated analysis log.
Justify a short period for the raw log from the security purpose. For analysis, the BfDI assessment of five weeks (BfDI) serves as a guide value, after which only counts remain.
Set log format, rotation and deletion so they match the period, including application logs and the system journal.
Check backups, staging and exports for logs they contain and align their retention with the period or exclude the logs.
Update the record of processing and the privacy policy. In each maintenance cycle compare the oldest existing log with the period, especially after updates and server moves.
The last step is the one most easily dropped in practice, because the setting is correct once and rarely gets checked again. A package update, a server move or a new protection layer in front of the shop brings its own logs and its own defaults. Alongside disk usage and error logs, which monitoring watches, the age of the oldest log therefore belongs among the values that should be checked regularly. How logs fill a partition under their default settings is described in the article on disk space monitoring.
In a maintenance contract these points come together. The GDPR updates cover maintaining the privacy policy with its storage periods and the record of processing activities. Web server configuration and backups are part of the technical support described under services. Response times and packages are set out in the SLA maintenance contract. That way period, configuration and documentation sit in one place and do not drift apart.
Sources
Related Articles
Consent Maintenance 2026: Banners and Script Drift
After every update scripts load before consent: how a script inventory, an audit log, blocked-by-default tags and CSP keep the consent setup current.
GDPR-Compliant Data Backup and Retention for Shops
Reconcile GDPR and backups: legal basis, retention periods, deletion concept, right to erasure, encryption, data processing agreements and EU storage location.
WordPress security updates: what old branches still get
WordPress 7.1.2 closed a critical flaw and the fix was backported to 4.7 as a courtesy. What older branches receive, what they do not, and when to move up.