goaccess(1)
๐ NAME ๐
goaccess โ fast web log analyzer and interactive viewer. Yep bestie, this is the goaccess(1) page from User Manuals. โจ
๐ SYNOPSIS ๐
goaccess [filename] [options...] [-c][-M][-H][-q][-d][...]
๐ธ DESCRIPTION ๐ธ
Okay so goaccess is an open source, real-time log analyzer and interactive viewer that runs in a terminal on *nix systems or directly in your browser. Designed with system administrators, DevOps engineers, and security professionals in mind, it delivers fast, actionable HTTP statistics and visual server reports on the fly. GoAccess parses your web server logs in real time and presents the data directly in the terminal or via a live HTML dashboard, making it easy to monitor traffic, detect anomalies, and troubleshoot issues instantly. ๐
๐ General Statistics ๐
This panel gives a summary of several metrics, such as the number of valid and invalid requests, time taken to analyze the dataset, unique visitors, requested files, static files (CSS, ICO, JPG, etc), HTTP referrers, 404s, size of the parsed log file and bandwidth consumption. Itโs giving โdashboard but make it terminalโ energy. ๐ซถ
๐ Unique visitors ๐
This panel shows metrics such as hits, unique visitors and cumulative bandwidth per date. HTTP requests containing the same IP, the same date, and the same user agent are considered a unique visitor. By default, it includes web crawlers/spiders.
Optionally, date specificity can be set to the hour level using --date-spec=hr which will display dates such as 05/Jun/2016:16, or to the minute level producing 05/Jun/2016:16:59. This is great if you want to track your daily traffic at the hour or minute level. โฐ
๐ Requested files ๐
This panel displays the most requested (non-static) files on your web server. It shows hits, unique visitors, and percentage, along with the cumulative bandwidth, protocol, and the request method used.
๐ผ๏ธ Requested static files ๐ผ๏ธ
Lists the most frequently static files such as: JPG, CSS, SWF, JS, GIF, and PNG file types, along with the same metrics as the last panel. Additional static files can be added to the configuration file.
๐ซ 404 or Not Found ๐ซ
Displays the same metrics as the previous request panels, however, its data contains all pages that were not found on the server, or commonly known as 404 status code. Not the vibe, but extremely useful. ๐
๐ Hosts ๐
This panel has detailed information on the hosts themselves. This is great for spotting aggressive crawlers and identifying who's eating your bandwidth.
Expanding the panel can display more information such as host's reverse DNS lookup result, country of origin and city. If the -a argument is enabled, a list of user agents can be displayed by selecting the desired IP address, and then pressing ENTER.
๐ป Operating Systems ๐ป
This panel will report which operating system the host used when it hit the server. It attempts to provide the most specific version of each operating system.
๐ฆ Browsers ๐ฆ
This panel will report which browser the host used when it hit the server. It attempts to provide the most specific version of each browser.
๐ฐ๏ธ Visit Times ๐ฐ๏ธ
This panel will display an hourly report. This option displays 24 data points, one for each hour of the day.
Optionally, hour specificity can be set to the tenth of an hour level using --hour-spec=min which will display hours as 16:4. This is great if you want to spot peaks of traffic on your server.
๐ Virtual Hosts ๐
This panel will display all the different virtual hosts parsed from the access log. This panel is displayed if %v is used within the log-format string.
๐ Referrers URLs ๐
If the host in question accessed the site via another resource, or was linked/diverted to you from another host, the URL they were referred from will be provided in this panel. See --ignore-panel in your configuration file to enable it. disabled by default.
๐ Referring Sites ๐
This panel will display only the host part but not the whole URL. The URL where the request came from.
๐บ๏ธ Geo Location ๐บ๏ธ
Determines where an IP address is geographically located. Statistics are broken down by continent and country, and when city-level GeoIP data is available it also lists the individual cities for each hit. It needs to be compiled with GeoLocation support.
๐ HTTP Status Codes ๐
The values of the numeric status code to HTTP requests.
๐ฐ๏ธ ASN ๐ฐ๏ธ
This panel displays ASN (Autonomous System Numbers) data for GeoIP2 and legacy databases. Great for detecting malicious traffic and blocking accordingly.
๐ Remote User (HTTP authentication) ๐
This is the userid of the person requesting the document as determined by HTTP authentication. If the document is not password protected, this part will be - just like the previous one. This panel is not enabled unless %e is given within the log-format variable.
๐๏ธ Cache Status ๐๏ธ
If you are using caching on your server, you may be at the point where you want to know if your request is being cached and served from the cache. This panel shows the cache status of the object the server served. This panel is not enabled unless %C is given within the log-format variable. The status can be either MISS, BYPASS, EXPIRED, STALE, UPDATING, REVALIDATED or HIT.
๐จ MIME Types ๐จ
This panel specifies Media Types (formerly known as MIME types) and Media Subtypes which will be assigned and listed underneath. This panel is not enabled unless %M is given within the log-format variable. See https://www.iana.org/assignments/media-types/media-types.xhtml for more details.
๐ Encryption Settings ๐
This panel shows the SSL/TLS protocol and cipher suite. If %g is present, the negotiated key exchange group is nested beneath its cipher suite, or directly beneath the protocol when no cipher is available. This panel is not enabled unless %K is given within the log-format variable.
๐ฃ UTM Campaigns ๐ฃ
This panel groups campaign traffic by medium, source, campaign, content, and term. It also recognizes campaign ID, source platform, creative format, and marketing tactic parameters when present. Values are extracted from the requested URL and displayed as an expandable hierarchy.
GoAccess panels can be reordered and their subitems expanded or collapsed from the terminal interface, keeping the most important metrics front and center. Chart metrics and scales are also adjustable on the fly via the interactive menu described below.
NOTE: Optionally and if configured, all panels can display the average time taken to serve the request.
๐พ STORAGE ๐พ
There are three storage options that can be used with GoAccess. Choosing one will depend on your environment and needs.
๐ง Default Hash Tables ๐ง
In-memory storage provides better performance at the cost of limiting the dataset size to the amount of available physical memory. GoAccess uses in-memory hash tables. It has very good memory usage and pretty good performance. This storage has support for on-disk persistence.
โ๏ธ CONFIGURATION โ๏ธ
Multiple options can be used to configure GoAccess. For a complete up-to-date list of configure options, run ./configure --help
--enable-debugโ Compile with debugging symbols and turn off compiler optimizations.--enable-utf8โ Compile with wide character support. Ncursesw is required.--enable-geoip=<legacy|mmdb>โ Compile with GeoLocation support. MaxMind's GeoIP is required.legacywill utilize the original GeoIP databases.mmdbwill utilize the enhanced GeoIP2 databases.--with-getlineโ Dynamically expands line buffer in order to parse full line requests instead of using a fixed size buffer of4096.--with-zlibโ Build with zlib support for reading gzipped logs. Disabled by default.--with-opensslโ Compile GoAccess with OpenSSL support for its WebSocket server.--with-zlibEnables optional zlib support to allow parsing of compressed log files (e.g.,.gz) directly without manual decompression.
โจ OPTIONS โจ
The following options can be supplied to the command or specified in the configuration file. If specified in the configuration file, long options need to be used without prepending -- and without using the equal sign =.
๐ฐ๏ธ LOG/DATE/TIME FORMAT ๐ฐ๏ธ
--time-format=<timeformat>โ Thetime-formatvariable followed by a space, specifies the log format time containing either a name of a predefined format (see options below) or any combination of regular characters and special format specifiers. They all begin with a percentage (%) sign. Seeman strftime. Like%Tor%H:%M:%S. Note that if a timestamp is given in microseconds,%fmust be used astime-format. If the timestamp is given in milliseconds%*must be used astime-format.--date-format=<dateformat>โ Thedate-formatvariable followed by a space, specifies the log format time containing either a name of a predefined format (see options below) or any combination of regular characters and special format specifiers. They all begin with a percentage (%) sign. Seeman strftime. Like%Y-%m-%d. Note that if a timestamp is given in microseconds,%fmust be used asdate-format. If the timestamp is given in milliseconds%*must be used asdate-format.--datetime-format=<date_time_format>โ The date and time format combines the two variables into a single option. This gives the ability to get the timezone from a request and convert it to another timezone for output. See--tz=<timezone>. They all begin with a percentage (%) sign. Seeman strftime. e.g.,%d/%b/%Y:%H:%M:%S %z. Note that if--datetime-formatis used,%xmust be passed in thelog-formatvariable to represent the date and time field.--log-format=<logformat>โ Thelog-formatvariable followed by a space or\tfor tab-delimited, specifies the log format string.
Okay so real quick on quoting before we move onโon the command line, a format that's got spaces in it must be wrapped in quotes so the shell hands it over as a single argument. But careful, bestie: those outer shell quotes must not get copied into the configuration file, because there the value is read literally. Like:
log-format { "ClientHost": "%h", "DownstreamContentSize": "%b" }
Also, a JSON log-format has to itself be valid JSON. So every format specifier goes in double quotes โ even the ones for values that are numbers in your input log, like "DownstreamContentSize": "%b". The matching input value can still totes be a JSON number tho, no cap.
And here's a shortcut, because we love convenience: instead of spelling out raw log/date/time formats, you can hand any of these predefined log format names to the log-format/date-format/time-format variables. GoAccess can even handle one predefined name in one variable and a different predefined name in another. Mix and match, it's giving versatility โจ
COMBINEDโ Combined Log FormatVCOMBINEDโ Combined Log Format with full Virtual Host fieldVCOMBINED_PORTโ Combined Log Format with required colon-delimited portCOMMONโ Common Log FormatVCOMMONโ Common Log Format with full Virtual Host fieldVCOMMON_PORTโ Common Log Format with required colon-delimited portW3Cโ W3C Extended Log File FormatSQUIDโ Native Squid Log FormatCLOUDFRONTโ Amazon CloudFront standard logs (legacy fixed schema)CLOUDSTORAGEโ Google Cloud StorageAWSELBโ Amazon Elastic Load BalancingAWSS3โ Amazon Simple Storage Service (S3)AWSALBโ Amazon Application Load BalancerCADDYโ Caddy JSON structured access logsTRAEFIKCLFโ Traefik's CLF flavor
VCOMBINED and VCOMMON keep the complete whitespace-delimited Virtual Host field, port and all if there is one. Their _PORT variants are the opposite vibe โ they require a separate colon-delimited port and drop it from the reported Virtual Host value.
Note: generally you need quotes around values that include whitespace, commas, pipes, quotes, and/or brackets. Inner quotes gotta be escaped, mkay.
Note: piping data into GoAccess won't pop a log/date/time configuration dialog at you ๐ญ you have to define it beforehand in your configuration file or on the command line.
Note: the default GoAccess format forCADDYis the'local/info'format. That said, if you need it, you can absolutely use a custom GoAccess log format to match your particular configuration. iykyk ๐
๐ USER INTERFACE OPTIONS ๐
-c,--config-dialogโ pops the log/time/date configuration window on program start. Only when curses is initialized, bestie.-i,--hl-headerโ color-highlights the active terminal panel โจ-m,--with-mouseโ enables mouse support on the main terminal dashboard ๐ฑ๏ธ--color=<fg:bg[attrs, PANEL]>โ specify custom colors for the terminal output.
Color Syntax
DEFINITION space/tab colorFG#:colorBG# [attributes,PANEL]
FG#= foreground color[-1...255](-1= default term color)BG#= background color[-1...255](-1= default term color)
Optionally you can slap color attributes on there (multiple attributes are comma-separated), such as: bold, underline, normal, reverse, blink.
And if you're feeling extra, you can apply custom colors per panel โ meaning a metric in the REQUESTS panel can be color A while the same metric in the BROWSERS panel is color B. Obsessed.
Available color definitions:
COLOR_MTRC_HITSCOLOR_MTRC_VISITORSCOLOR_MTRC_DATACOLOR_MTRC_BWCOLOR_MTRC_AVGTSCOLOR_MTRC_CUMTSCOLOR_MTRC_MAXTSCOLOR_MTRC_PROTCOLOR_MTRC_MTHDCOLOR_MTRC_HITS_PERCCOLOR_MTRC_HITS_PERC_MAXCOLOR_MTRC_VISITORS_PERCCOLOR_MTRC_VISITORS_PERC_MAXCOLOR_PANEL_COLSCOLOR_BARSCOLOR_ERRORCOLOR_SELECTEDCOLOR_PANEL_ACTIVECOLOR_PANEL_HEADERCOLOR_PANEL_DESCCOLOR_OVERALL_LBLSCOLOR_OVERALL_VALSCOLOR_OVERALL_PATHCOLOR_ACTIVE_LABELCOLOR_BGCOLOR_DEFAULTCOLOR_PROGRESS
See the configuration file for a sample color scheme ๐
--color-scheme=<1|2|3>โ pick your color scheme.1for the default grey scheme.2for the green scheme.3for the Monokai scheme (only shown if your terminal supports 256 colors).--crawlers-onlyโ parse and display only crawlers (bots) ๐ค--html-custom-css=<path/custom.css>โ specifies a custom CSS file path to load in the HTML report.--html-custom-js=<path/custom.js>โ specifies a custom JS file path to load in the HTML report.--html-report-title=<title>โ sets the HTML report page title and header.--html-refresh=<secs>โ refresh the HTML report every X seconds. The value has to be between1and60seconds. Default is set to refresh the HTML report every1second.--html-prefs=<JSON>โ set HTML report default preferences. Supply a valid JSON object containing the HTML preferences. It gives you the ability to customize each panel plot. See the example below.
Note: the JSON object you pass needs to be a one line JSON string. For instance,
--html-prefs='{"theme":"bright","perPage":5,"layout":"horizontal","showTables":true,"visitors":{"plot":{"chartType":"bar"}}}'
--json-pretty-printโ format JSON output using tabs and newlines.
Note: not recommended when you're outputting a real-time HTML report, because the WebSocket payload will be much much larger ๐ญ
--max-items=<number>โ the maximum number of items to display per panel. The maximum can be a number between1and n.
Note: only the CSV and JSON output allow a maximum number greater than the default value of366(or50in the real-time HTML output) items per panel.
--no-colorโ turn off colored output. This is the default output on terminals that don't support colors.--no-csv-summaryโ disable summary metrics on the CSV output.--no-progressโ disable parsing and hostname resolution progress metrics. Parsing progress shows total requests and requests per second. Hostname resolution progress shows resolved, total and pending hostnames.--no-tab-scrollโ disable scrolling through panels when TAB is pressed, or when a panel is selected using a numeric key.--no-html-last-updatedโ don't show the last updated field displayed in the generated HTML report.--no-parsing-spinnerโ don't show the progress metrics or the parsing spinner.--tz=<timezone>โ outputs the report date/time data in the given timezone. Heads up: it uses the canonical timezone name. e.g.Europe/BerlinorAmerica/ChicagoorAfrica/Cairo. If you give it an invalid timezone name, the output will be inGMT. See--datetime-formatto properly specify a timezone in the date/time format ๐
๐ฅ SERVER OPTIONS ๐ฅ
Note: this is just a WebSocket server to provide the raw real-time data. It is not a WebServer itself. To access your report's html file you'll still need your own HTTP server โ drop the generated report in its document root dir and open the html file in your browser. The browser will then open another WebSocket-connection to the ws-server you may set up here, to keep the dashboard up-to-date. ๐
--addr=<addr>โ specify the IP address to bind the server to. Otherwise it binds to0.0.0.0.
Usually there's no need to specify the address, unless you intentionally want to bind the server to a different address within your server.
--unix-socket=<addr>โ specify the UNIX-domain socket address to bind the server to. It's used instead of--addrand--port.--daemonizeโ run GoAccess as a daemon (only if--real-time-htmlis enabled).
Note: it's important to make use of absolute paths across GoAccess' configuration.
--user-name=<username>โ run GoAccess as the specified user.
Note: it's important to ensure the user or the user's group can access the input and output files as well as any other files needed. Other groups the user belongs to will be ignored. As such it's advised to run GoAccess behind a SSL proxy, since it's unlikely this user can access the SSL certificates.
--origin=<url>โ ensure clients send the specified origin header upon the WebSocket handshake.--pid-file=<path/goaccess.pid>โ write the daemon PID to a file when used along the--daemonizeoption.--port=<port>โ specify the port to use. By default GoAccess' WebSocket server listens on port7890.--real-time-htmlโ enable real-time HTML output.
GoAccess uses its own WebSocket server to push the data from the server to the client. See http://gwsocket.io for more details on how the WebSocket server works.
While following live logs, the General panel displays the total requests and the current requests-per-second rate in the same summary field. The rate is sampled once per second from changes in the total request count, and it starts after the initial log import โ so historical parsing throughput is not counted as live traffic. The --html-refresh interval controls how often the latest sample is sent to the browser, not the rate's sampling window. ๐ซถ
--ws-auth=<jwt[:secret]> | jwt:verify:secretโ enable WebSocket authentication using a JSON Web Token (JWT). This option supports two formats depending on whether the JWT is locally generated or externally fetched and verified:<jwt[:secret]>โ okay so this is your static JWT setup, with an optional secret for local generation or validation. If you only passjwt(like--ws-auth=jwt), GoAccess generates a JWT using a secret pulled from theGOACCESS_WSAUTH_SECRETenvironment variable โ or a default HS256-compatible secret if that env var is unset. If you include a secret (like--ws-auth=jwt:mysecret), it's used directly as the HS256 signing key, or read from a file if the value is a valid path (like--ws-auth=jwt:/path/to/secret.key). Slay.jwt:verify:secretโ this one turns on verification of an externally fetched JWT (like via--ws-auth-url). Theverifykeyword is literally saying "the JWT is coming from an external source," and the secret must be specified for validation. That secret can be a direct HS256 key (like--ws-auth=jwt:verify:mysecret), a file path (like--ws-auth=jwt:verify:/path/to/secret.key), or an environment variable name (like--ws-auth=jwt:verify:$JWT_SECRET). This format is required when using--ws-auth-urland optionally--ws-auth-refresh-urlto fetch and verify JWTs from external endpoints. Periodt.
When this option is used, the HTML report will not bootstrap the initial parsed data. Instead, it will only display the report if authentication succeeds, ensuring secure access to real-time data. Main character security energy, honestly.
The system processes this option as follows:
- For
<jwt[:secret]>: if no secret is provided, GoAccess generates a JWT locally using theGOACCESS_WSAUTH_SECRETenvironment variable or a default secret. If a secret is specified, it's used to sign the JWT (either directly or from a file). - For
jwt:verify:secret: the secret is mandatory and used to verify externally fetched JWTs. It must match the signing key used by the external authentication server (e.g., at--ws-auth-url).
Requires to build GoAccess with --with-openssl.
--ws-auth-expire=<secs>โ sets the time after which the JWT expires. Defaults to 8 hours (28800seconds) if you don't specify it. Only available for locally generated JWT, bestie.
Users can specify the expiration time in various formats. The value is converted to seconds for JWT expiration validation. Supported formats:
"3600"โ 3600 seconds"120s"โ 2 minutes"24h"โ 24 hours = 86,400 seconds"10m"โ 10 minutes = 600 seconds"10d"โ 10 days = 864,000 seconds
The expiration time controls how long the JWT remains valid after issuance, ensuring secure WebSocket connections. It's giving timed-access glamour.
--ws-auth-url=<url>โ specifies the URL where GoAccess fetches the initial JWT to authenticate the WebSocket connection.
When this option is used, GoAccess sends a GET request to the specified URL to fetch an initial JWT. The response must be a JSON object containing status, access_token, refresh_token, and expires_in fields.
Example: --ws-auth-url=https://site.com/api/get-auth-token
When fetching the token, GoAccess uses { credentials: 'include' } as part of the request to securely retrieve the access token based on the user's existing authentication session in your system, ensuring token retrieval is safe as long as your users are authenticated.
This option allows you to integrate your existing authentication system with the GoAccess dashboard, using token retrieval endpoints. Lowkey iconic integration behavior.
--ws-auth-refresh-url=<url>โ specifies the URL where GoAccess fetches a new JWT when the current one is about to expire.
GoAccess proactively refreshes the JWT 60 seconds before expiration by sending a POST request with the refresh_token to this URL. If not provided, it defaults to the same URL as --ws-auth-url.
Example: --ws-auth-refresh-url=https://site.com/api/refresh-token
The response format should match that of the initial authentication URL.
๐ WebSocket Authentication Flow ๐
GoAccess offers flexible authentication options, supporting both stateless and stateful approaches. In the stateless approach, the refresh token is obtained without cookies or CSRF protection; your backend validates the refresh token's signature and issues a new access token. Alternatively, the stateful approach allows the initial fetch to issue JWTs along with a csrf_token, which is stored in the session. The subsequent refresh request (POST) then performs a CSRF check, requiring the X-CSRF-TOKEN header to match the session's token. fr fr, that's the whole vibe.
Initial Authentication:
- When started with
--ws-auth-url=<url>, GoAccess sends a GET request to fetch an initial JWT. - The expected successful response format:
{
"status" : "success",
"access_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"csrf_token" : "3RRjNeR4RTXHmrV1cECkyUmmKeRxm4lzkI0eq41o",
"refresh_token" : "refresh123xyz",
"expires_in" : 3600
}
- If authentication fails, the endpoint should return:
{
"status": "error",
"message": "User not authenticated"
}
Token Refreshing:
- GoAccess refreshes the JWT 60 seconds before expiration by sending a POST request to the specified URL (defaults to
--ws-auth-urlif--ws-auth-refresh-urlis not set):
{ "refresh_token": "refresh123xyz" }
GoAccess supports both stateless and stateful authentication. For stateless, no cookies or CSRF are required; your backend validates the refresh token signature. For stateful, include a csrf_token in the initial response; GoAccess sends it as X-CSRF-TOKEN in the refresh request, which your backend must validate against the session.
Periodic Token Validation:
- After refreshing, GoAccess confirms the updated JWT's validity with the WebSocket server by sending:
{ "action": "validate_token", "token": "current-jwt" }
- The WebSocket server tracks the verified JWT's
expclaim and closes the connection when it expires, even if the client does not send another message. - If token refresh fails or returns an unusable token, the browser clears its credentials and closes the authenticated WebSocket connection.
๐จ Important Note: For these options to function, you must specify--ws-auth=jwt:verify:<secret>where<secret>can be:
- A path to a file containing the secret key (e.g.,
/path/to/secret.key) - An environment variable name that holds the secret (e.g.,
$JWT_SECRET) - The actual HS256 secret key as a string (e.g.,
mysecretkey123)
Example: --ws-auth=jwt:verify:/path/to/secret.key
--ws-url=<[scheme://]url[:port]>โ URL to which the WebSocket server responds. This is the URL supplied to the WebSocket constructor on the client side. Ngl, this one's important.
Optionally, it is possible to specify the WebSocket URI scheme, such as ws:// or wss:// for unencrypted and encrypted connections. e.g., wss://goaccess.io
If GoAccess is running behind a proxy, you could set the client side to connect to a different port by specifying the host followed by a colon and the port. e.g., goaccess.io:9999
By default, it will attempt to connect to the generated report's hostname. If GoAccess is running on a remote server, the host of the remote server should be specified here. Also, make sure it is a valid host and NOT an http address.
--ping-interval=<secs>โ enable WebSocket ping with specified interval in seconds. This helps prevent idle connections getting disconnected. Keep those connections alive, bestie.--fifo-in=<path/file>โ creates a named pipe (FIFO) that reads from on the givenpath/file.--fifo-out=<path/file>โ creates a named pipe (FIFO) that writes to the givenpath/file.--ssl-cert=<cert.crt>โ path to TLS/SSL certificate. In order to enable TLS/SSL support, GoAccess requires that--ssl-certand--ssl-keyare used.
Only if configured using --with-openssl.
--ssl-key=<priv.key>โ path to TLS/SSL private key. In order to enable TLS/SSL support, GoAccess requires that--ssl-certand--ssl-keyare used.
Only if configured using --with-openssl.
๐๏ธ FILE OPTIONS ๐๏ธ
-โ the log file to parse is read from stdin. The classic pipe-and-go moment.-f,--log-file=<logfile>โ specify the path to the input log file. If set in the config file, it will take priority over-ffrom the command line. Sneaky config file behavior, iykyk.-S,--log-size=<bytes>โ specify the log size in bytes. This is useful when piping in logs for processing in which the log size can be explicitly set.-l,--debug-file=<debugfile>โ send all debug messages to the specified file. Debug tea, collected safely.-p,--config-file=<configfile>โ specify a custom configuration file to use. If set, it will take priority over the global configuration file (if any).--external-assetsโ output HTML assets to external JS/CSS files. Great if you are setting up Content Security Policy (CSP). This will create two separate files,goaccess.jsandgoaccess.css, in the same directory as yourreport.htmlfile.--invalid-requests=<filename>โ log invalid requests to the specified file. Catch those messy requests.--unknowns-log=<filename>โ log unknown browsers and OSs to the specified file.--no-global-configโ do not load the global configuration file. This directory should normally be/usr/local/etc, unless specified with--sysconfdir=/dir. See--dcfoption for finding the default configuration file.
๐ PARSE OPTIONS ๐
-a,--agent-listโ enable a list of user-agents by host. For faster parsing, do not enable this flag. Highkey a speed tradeoff, bestie.-d,--with-output-resolverโ enable IP resolver onHTML|JSON|CSVoutput. Hostname resolution progress is shown unless progress metrics are disabled.-e,--exclude-ip=<IP|IP-range>โ keeps an IPv4 or IPv6 out of the count ๐ heads up tho: this only applies during access log data processing โ it does not exclude persisted data. Ranges work too, just drop a dash between the IPs (start-end).
Examples:
exclude-ip 127.0.0.1
exclude-ip 192.168.0.1-192.168.0.100
exclude-ip ::1
exclude-ip 0:0:0:0:0:ffff:808:804-0:0:0:0:0:ffff:808:808
-j,--jobs=<1-6>โ how many parallel processing threads the program gets to use โจ it sets the degree of concurrency when analyzing log data, so multiple tasks can be processed simultaneously. Defaults to1thread. Fr fr the usual move is to set jobs based on your available hardware resources, like the number of CPU cores.-H,--http-protocol=<yes|no>โ set/unset HTTP request protocol. This creates a request key containing the request protocol + the actual request ๐ฅ-M,--http-method=<yes|no>โ set/unset HTTP request method. This creates a request key containing the request method + the actual request ๐ฅ-o,--output=<path/file.[json|csv|html]>โ writes output to stdout given one of these files + the matching extension for the output format ๐
/path/file.csv - Comma-separated values (CSV)
/path/file.json - JSON (JavaScript Object Notation)
/path/file.html - HTML
-q,--no-query-stringโ ignore the request's query string, i.e.www.google.com/page.htm?query=>www.google.com/page.htm๐ฆ
Note: removing the query string can greatly decrease memory consumption, especially on timestamped requests. lowkey a glow-up for your RAM ๐ญ
-r,--no-term-resolverโ disable IP resolver on terminal output.--444-as-404โ treat the non-standard status code444as404.--4xx-to-unique-countโ add 4xx client errors to the unique visitors count ๐--anonymize-ipโ anonymize the client IP address. This option sets the last octet of IPv4 user IP addresses and the last 80 bits of IPv6 addresses to zeros ๐ต๏ธโ๏ธ e.g.192.168.20.100=>192.168.20.0, e.g.2a03:2880:2110:df07:face:b00c::1=>2a03:2880:2110:df07::
Note: this deactivates -a. not both bestie, pick a lane ๐
--chunk-size=<256-32768>โ determines the number of lines that form a chunk. This parameter influences the size of the data processed concurrently by each thread, which is what lets the file reading and processing tasks be parallelized โก the value of chunk-size affects how efficient the parallel processing is, and you can adjust it based on stuff like system resources and the characteristics of the input data.
Low values: if chunk-size is set too low, it might result in inefficient processing. For instance, if each chunk contains a very small number of lines, the overhead of managing and coordinating parallel processing might outweigh the benefits ๐
Large values: conversely, if chunk-size is set too high, it could lead to resource exhaustion. Each chunk represents a portion of data that a thread processes in parallel. Setting chunk-size to an excessively large value might cause memory issues, particularly if there are many parallel threads running simultaneously ๐ฌ
--anonymize-level=<1|2|3>โ specifies the anonymization levels:1=> default,2=> strong,3=> pedantic ๐ here's the bits-hidden tea:- IPv4: level 1 =>
8, level 2 =>16, level 3 =>24 - IPv6: level 1 =>
64, level 2 =>80, level 3 =>96
- IPv4: level 1 =>
--all-static-filesโ include static files that contain a query string. e.g.,/fonts/fontawesome-webfont.woff?v=4.0.3๐ธ-b,--browsers-file=<path>โ by default GoAccess parses an "essential/basic" curated list of browsers & crawlers. If you need to add additional browsers, use this option ๐ include an additional delimited list of browsers/crawlers/feeds etc. Seeconfig/browsers.listfor an example orhttps://raw.githubusercontent.com/allinurl/goaccess/master/config/browsers.list--concat-vhost-reqโ prepend the virtual host to the request field, so the top requests show which virtual host they belong to ๐ it requires the virtual host%vto be part of thelog-formatvariable.--date-spec=<date|hr|min>โ set the date specificity to eitherdate(default),hrto display hours, orminto display minutes appended to the date โจ
This is used in the visitors panel. It's useful for tracking visitors at the hour level. For instance, an hour specificity would yield displaying traffic as 18/Dec/2010:19 or minute specificity 18/Dec/2010:19:59.
--double-decodeโ decode double-encoded values. This includes user-agent, request, and referrer ๐--enable-panel=<PANEL>โ enable parsing and displaying the given panel ๐ซถ
Available panels:
VISITORS
REQUESTS
REQUESTS_STATIC
NOT_FOUND
HOSTS
OS
BROWSERS
VISIT_TIMES
VIRTUAL_HOSTS
REFERRERS
REFERRING_SITES
STATUS_CODES
REMOTE_USER
CACHE_STATUS
GEO_LOCATION
MIME_TYPE
TLS_TYPE
UTM_CAMPAIGNS
--fname-as-vhost=<regex>โ use log filename(s) as virtual host(s). A POSIX regex is passed in to extract the virtual host from the filename ๐ฆ e.g.,--fname-as-vhost='[a-z]*.[a-z]*'can be used to extractawesome.com.log=>awesome.com.--hide-referrer=<NEEDLE>โ hide a referrer but still count it ๐ wild cards are allowed in the needle, i.e.,*.bing.com.--hour-spec=<hr|min>โ set the time specificity to eitherhour(default) orminto display the tenth of an hour appended to the hour โฐ
This is used in the time distribution panel. It's useful for tracking peaks of traffic on your server at specific times.
--ignore-crawlersโ ignore crawlers from being counted ๐ท๏ธ--unknowns-as-crawlersโ classify unknown OS and browsers as crawlers.--ignore-panel=<PANEL>โ ignore parsing and displaying the given panel ๐
Available panels:
VISITORS
REQUESTS
REQUESTS_STATIC
NOT_FOUND
HOSTS
OS
BROWSERS
VISIT_TIMES
VIRTUAL_HOSTS
REFERRERS
REFERRING_SITES
STATUS_CODES
REMOTE_USER
CACHE_STATUS
GEO_LOCATION
MIME_TYPE
TLS_TYPE
UTM_CAMPAIGNS
--ignore-referrer=<referrer>โ ignore referrers from being counted. Wildcards allowed ๐ซ e.g.,*.domain.comww?.domain.*--ignore-statics=<req|panel>โ ignore static file requests.
req Only ignore request from valid requests
panels Ignore request from panels.
Note that it will count them towards the total number of requests. so like, they're hidden but still on the roster bestie ๐
--ignore-status=<CODE>โ ignore parsing and displaying one or multiple status code(s). For multiple status codes, use this option multiple times ๐--keep-last=<num_days>โ keep the last specified number of days in storage. This will recycle the storage tables ๐ธ e.g., keep & show only the last 7 days.--no-ip-validationโ disable client IP validation. Useful if IP addresses have been obfuscated before being logged ๐ the log still needs to contain a placeholder for%h, usually it's a resolved IP. e.g.ord37s19-in-f14.1e100.net.--no-strict-statusโ disable HTTP status code validation. Some servers would record this value only if a connection was established to the target and the target sent a response. Otherwise, it could be recorded as-.--num-tests=<number>โ number of lines from the access log to test against the provided log/date/time format ๐งช by default, the parser is set to test10lines. If set to0, the parser won't test any lines and will parse the whole access log. If a line matches the given log/date/time format before it reaches<number>, the parser will consider the log to be valid, otherwise GoAccess will returnEXIT_FAILUREand display the relevant error messages ๐ญ--process-and-exitโ parse log and exit without outputting data. Useful if we're looking to only add new data to the on-disk database without outputting to a file or a terminal โจ--real-osโ display real OS names. e.g,Windows XP,Snow Leopard๐ป--sort-panel=<PANEL,FIELD,ORDER>โ sort panel on initial load. Sort options are separated by comma. Options are in the form:PANEL,METRIC,ORDER๐
Available metrics:
BY_HITS - Sort by hits
BY_VISITORS - Sort by unique visitors
BY_DATA - Sort by data
BY_BW - Sort by bandwidth
BY_AVGTS - Sort by average time served
BY_CUMTS - Sort by cumulative time served
BY_MAXTS - Sort by maximum time served
BY_PROT - Sort by http protocol
BY_MTHD - Sort by http method
Available orders:
ASC
DESC
--static-file=<extension>โ add static file extension. e.g.:.mp3๐ต extensions are case sensitive.
๐ GEOLOCATION OPTIONS ๐
-g,--std-geoipโ standard GeoIP database for less memory usage ๐ซถ--exclude-asn=<ASN>โ exclude requests whose client address resolves to the given Autonomous System Number. The option can be repeated and accepts either the numeric form, such as8075, or the AS-prefixed form, such asAS8075๐
...and this whole thing only works when GoAccess is built with GeoIP2 support and you've fed it an ASN database through --geoip-database. If you set up ASN exclusions without an ASN-capable database, GoAccess literally just exits with an error, no discussion ๐. Also important: exclusions kick in as records are parsed, so they will not go back and remove matching records that were already restored from persistent storage. Past-you's data stays, bestie.
--geoip-database=<geofile>โ point it at your GeoIP database file, likeGeoLiteCity.dat๐บ๏ธโจ
If you're on GeoIP2, you need to grab the GeoLite2 City or Country database from MaxMind.com and hand the path over with --geoip-database. You can also pick up updated database files for GeoIP legacy โ those live as the GeoLite Legacy Databases from MaxMind.com. IPv4 and IPv6 files are both supported, so no stress there. And for the updated DB URLs, check the default GoAccess configuration file ๐
Note:--geoip-city-datais an alias of--geoip-database. Same thing, different name, iconic behaviour.
๐ OTHER OPTIONS
-h,--helpโ the help. That's it. That's the whole description ๐-s,--storageโ shows you the current storage method. i.e.,B+ Tree,Hash.-V,--versionโ prints the version info and dips out (exits) ๐--dcfโ shows the path of the default config file when-pisn't being used.
๐พ PERSISTENCE STORAGE OPTIONS
--persistโ saves your parsed data to disk ๐ซถ. If database files already exist, they get overwritten, no cap. This should be set to the first dataset. Peep the examples.--restoreโ loads back all that previously stored data from disk. If you're only reading persisted data, the database files gotta exist, periodt. Heads up: the--http-methodand--http-protocolsettings must match the ones used to create that database, because those are what determine how request keys get grouped. See--persistand the examples.--db-path=<dir>โ the path where the on-disk database files live. Default value is the/tmpdirectory. Classic.
๐จ CUSTOM LOG/DATE FORMAT
GoAccess can parse, like, virtually any web log format. Fr fr. ๐
The predefined ones include Common Log Format (CLF), Combined Log Format (XLF/ELF) โ which includes virtual host โ Amazon CloudFront (Download Distribution), Google Cloud Storage and W3C format (IIS).
And on top of all that, GoAccess allows any custom format string too. Sky's the limit ๐
There are two ways to configure the log format. The easiest is to run GoAccess with -c and it'll pop open a configuration window for you. Otherwise you can set it under ~/.goaccessrc or the %sysconfdir%.
time-format
The time-format variable, followed by a space, specifies the log format time, and it can contain any combination of regular characters and special format specifiers. They all begin with a percentage (%) sign. See man strftime. Example: %T or %H:%M:%S.
Note: if a timestamp is given in microseconds,%fmust be used astime-format, or%*if the timestamp is given in milliseconds.
date-format
The date-format variable, followed by a space, specifies the log format date, and it can contain any combination of regular characters and special format specifiers. They all begin with a percentage (%) sign. See man strftime. e.g., %Y-%m-%d.
Note: if a timestamp is given in microseconds,%fmust be used asdate-format, or%*if the timestamp is given in milliseconds.
log-format
The log-format variable, followed by a space or \t, specifies the log format string.
Now for the actual specifier lineup, because this is the part everyone screenshots ๐ธ:
%xโ a date and time field matching thetime-formatanddate-formatvariables. You use this when you're given a timestamp, or when the date & time are concatenated into a single string (e.g.,1501647332or20170801235000) instead of the date and time sitting in two separate variables.%tโ the time field matching thetime-formatvariable.%dโ the date field matching thedate-formatvariable.%vโ the canonical Server Name of the server serving the request (Virtual Host).%pโ the server port. It has to be a number from0through65535, and it's discarded after parsing. Bye ๐%eโ the userid of the person requesting the document, as determined by HTTP authentication.%Cโ the cache status of the object the server served.%hโ host (the client IP address, either IPv4 or IPv6).%rโ the request line from the client. This requires specific delimiters around the request (as single quotes, double quotes, or anything else) so it's parsable. If not, you gotta use a combination of special format specifiers as%m %U %H.%qโ the query string.%mโ the request method.%Uโ the URL path requested.
Note: if the query string is in%U, there's no need to use%q. However, if the URL path doesn't include any query string, you may use%qand the query string will be appended to the request.
%Hโ the request protocol.%sโ the status code that the server sends back to the client.%bโ the size of the object returned to the client.%Rโ the "Referrer" HTTP request header.%uโ the user-agent HTTP request header.%gโ the negotiated TLS key exchange group. (In Nginxlog_format:$ssl_curve)%Kโ the TLS encryption settings chosen for the connection. (In ApacheLogFormat:%{SSL_PROTOCOL}x)%kโ the TLS encryption settings chosen for the connection. (In ApacheLogFormat:%{SSL_CIPHER}x)%Mโ the MIME-type of the requested resource. (In ApacheLogFormat:%{Content-Type}o)%Dโ the time taken to serve the request, in microseconds as a decimal number.%Tโ the time taken to serve the request, in seconds with milliseconds resolution.%Lโ the time taken to serve the request, in milliseconds as a decimal number.%nโ the time taken to serve the request, in nanoseconds.%^โ ignore this field. Not me ignoring it ๐%~โ move forward through the log string until a non-space (!isspace) char is found.~hโ the host (the client IP address, either IPv4 or IPv6) in a X-Forwarded-For (XFF) field.
It uses a special specifier which consists of a tilde before the host specifier, followed by the character(s) that delimit the XFF field, which are enclosed by curly braces. i.e., "~h{, }"
For example, "~h{, }" is used in order to parse "11.25.11.53, 17.68.33.17" โ a field delimited by a comma and a space (enclosed by double quotes) ๐
Here's the little cheat sheet, table-free for your scrolling pleasure:
- XFF field
"192.1.2.3, 192.68.33.17, 192.1.1.2"โ specifier"~h{, }" - XFF field
"192.1.2.12", "192.68.33.17"โ specifier~h{", } - XFF field
192.1.2.12, 192.68.33.17โ specifier~h{, } - XFF field
192.1.2.14 192.68.33.17 192.1.1.2โ specifier~h{ }
Note: in order to get the average, cumulative and maximum time served in GoAccess, you'll need to start logging response times in your web server. In Nginx you can add$request_timeto your log format, or%Din Apache.
Important: if multiple time served specifiers are used at the same time, the first option specified in the format string takes priority over the other specifiers. First come, first served, literally.
GoAccess requires the following fields, no exceptions bestie:
%ha valid IPv4/6%da valid date%rthe request
๐น๏ธ INTERACTIVE MENU
Okay this is the fun part, the whole keyboard is basically a controller ๐ฎโจ
F1orhโ main help.F5โ redraw the main window.qโ quit the program, current window, or collapse the active module.oorENTERโ expand the selected module or open a window.+โ expand the selected item's children when a module is already expanded.-โ collapse the selected item's children when a module is already expanded.0-9andShift+0โ set the selected module to active.pโ reorder the dashboard panels interactively (pressporP).jโ scroll down within the expanded module.kโ scroll up within the expanded module.cโ set or change the scheme color ๐จrโ toggle reverse order of chart bars for the active module.mโ cycle chart metric forward for the active module (hits, visitors, bandwidth).Mโ cycle chart metric backward for the active module.lโ toggle logarithmic scale for chart bars in the active module.TABโ forward iteration of modules. Starts from the current active module.SHIFT+TABโ backward iteration of modules. Starts from the current active module.^fโ scroll forward one screen within an active module.^bโ scroll backward one screen within an active module.sโ sort options for the active module./โ search across all modules (regex allowed) ๐nโ find the position of the next occurrence across all modules.gโ move to the first item or top of screen.Gโ move to the last item or bottom of screen.
๐ EXAMPLES ๐
๐ก Heads up bestie: piping data into GoAccess won't prompt a log/date/time configuration dialog. So you gotta define it beforehand โ either in your configuration file or on the command line. No shortcuts, sorry ๐ซถ
โจ DIFFERENT OUTPUTS โจ
Wanna output to a terminal and generate an interactive report? Say less:
# goaccess access.log
Generate an HTML report:
# goaccess access.log -a -o report.html
Generate a JSON report:
# goaccess access.log -a -d -o report.json
Generate a CSV file:
# goaccess access.log --no-csv-summary -o report.csv
GoAccess also lets you do real-time monitoring straight from stdin, which is honestly iconic:
# tail -f access.log | goaccess -
Wanna filter while keeping the pipe open for real-time analysis? Periodt:
# tail -f access.log | grep -i --line-buffered 'firefox' |
goaccess --log-format=COMBINED -
Parse from the beginning of the file while maintaining the pipe:
# tail -f -n +0 access.log | grep -i --line-buffered 'firefox' |
goaccess --log-format=COMBINED -o report.html --real-time-html -
Convert the log date timezone to Europe/Berlin:
# goaccess access.log --log-format='%h %^[%x] "%r" %s %b "%R"
"%u"' --datetime-format='%d/%b/%Y:%H:%M:%S %z' --tz=Europe/Berlin
--date-spec=min
๐ MULTIPLE LOG FILES ๐
Parse multiple logs by passing them to the command line:
# goaccess access.log access.log.1
Parse from a pipe while also reading regular files (append - for stdin):
# cat access.log.2 | goaccess access.log access.log.1 -
๐ Note that the single dash is appended to the command line to let GoAccess know that it should read from the pipe.
Process all compressed log files plus the current log:
# zcat access.log.*.gz | goaccess access.log -
๐ Note: on macOS, usegunzip -cinstead ofzcat. ๐๏ธ Note: if GoAccess was built with--with-zlib, it can parse.gzfiles directly without external decompression:
# goaccess access.log access.log.1.gz access.log.2.gz
๐ REAL-TIME HTML OUTPUT ๐
Generate a real-time HTML report:
# goaccess access.log -o /usr/share/nginx/html/site/report.html
--real-time-html
Specify the WebSocket URL explicitly:
# goaccess access.log -o report.html --real-time-html --ws-
url=goaccess.io
Use a custom port:
# goaccess access.log -o report.html --real-time-html --port=9870
Bind WebSocket to a specific address:
# goaccess access.log -o report.html --real-time-html
--addr=127.0.0.1
๐ Note: for TLS/SSL real-time output, use--ssl-cert=<cert.crt>and--ssl-key=<priv.key>. If GoAccess is running behind a reverse proxy, set the WebSocket URL to include the proxy path and port, e.g.:
# goaccess access.log -o report.html --real-time-html --ws-
url=goaccess.io:8080/ws
๐ธ WORKING WITH DATES ๐ธ
All requests from a specific date to end of file:
# sed -n '/05Dec2010/,$ p' access.log | goaccess -a -
Using a relative date (one week ago):
# sed -n '/'$(date '+%d%b%Y' -d '1 week ago')'/,$ p' access.log |
goaccess -a -
Parse a specific date range:
# sed -n '/5Nov2010/,/5Dec2010/ p' access.log | goaccess -a -
Keep only the last 5 days of data:
# goaccess access.log --keep-last=5
๐ฆ VIRTUAL HOSTS ๐ฆ
Use --concat-vhost-req to prepend the virtual host or server block (%v) to the request field. Cute, right?
Append virtual host manually:
# awk '$8=$1$8' access.log | goaccess -a -
Exclude a list of virtual hosts:
# grep -v "`cat exclude_vhost_list_file`" vhost_access.log |
goaccess -
๐ FILES, STATUS CODES & BOTS ๐
Parse only specific page types (html, htm, php):
# awk '$7~/.html|.htm|.php/' access.log | goaccess -
Parse page views without extensions:
# awk '$7!~/..*$/' access.log | goaccess -
Filter by a single status code (e.g., 500):
# awk '$9~/500/' access.log | goaccess -
Filter by multiple status codes (3xx or 5xx):
# tail -f -n +0 access.log | awk '$9~/3[0-9]{2}|5[0-9]{2}/' |
goaccess -o out.html -
Estimate bot traffic ๐ค:
# tail -F -n +0 access.log | grep -i --line-buffered 'bot' |
goaccess -
๐ง SERVER ๐ง
Run GoAccess at lower CPU priority (be nice to your server, bestie):
# nice -n 19 goaccess -f access.log -a
Pipe logs from a remote server:
# ssh -n root@server 'tail -f /var/log/apache2/access.log' |
goaccess -
๐ Note: SSH requires -n so GoAccess can read from stdin. Use SSH keys for authentication.
๐ INCREMENTAL LOG PROCESSING ๐
GoAccess can process logs incrementally by persisting data to disk, then restoring it and appending new data. It tracks inodes, the last line parsed, and the last timestamp per file. Very main character of it.
๐ Note: if the inode doesn't match, all lines are parsed. If it matches, the remaining lines are read and the count/timestamp updated. Log lines with a timestamp โค the stored timestamp are skipped. Piped data works off the timestamp of the last line read.
โ ๏ธ Warning: piped data may produce duplicate entries, since multiple consecutive lines can share the same timestamp. Best practice is to parse directly with GoAccess rather than piping for incremental processing. Fr fr, don't do it.
Persist last month's log:
# goaccess access.log.1 --persist
Append this month's log and preserve:
# goaccess access.log --restore --persist
Read persisted data only:
# goaccess --restore
๐ซ Notes
GoAccess keeps track of inodes of all the files processed (assuming files will stay on the same partition). On top of that, it extracts a snippet of data from the log along with the last line parsed of each file and the timestamp of the last line parsed. e.g.:
inode:29627417|line:20012|ts:20171231235059
First it compares whether the snippet matches the log being parsed โ if it does, it assumes the log hasn't changed dramatically, e.g., hasn't been truncated. If the inode does not match the current file, it parses all lines. If the current file does match the inode, it then reads the remaining lines and updates the count of lines parsed and the timestamp. As an extra precaution, it won't parse log lines with a timestamp โค the one stored.
Piped data works based off the timestamp of the last line read. For instance, it will parse and discard all incoming entries until it finds a timestamp >= the one stored.
For instance:
// last month access log
# goaccess access.log.1 --persist
then, load it with
// append this month access log, and preserve new data
# goaccess access.log --restore --persist
To read persisted data only (without parsing new data)
# goaccess --restore
โญ NOTES โญ
Every active panel has a total of 366 items โ or 50 in the real-time HTML report. You can customize the number of items using max-items. And ngl, HTML, CSV and JSON output allow a maximum number greater than the default value of 366 items per panel. Slay.
A hit is a request (a line in the access log), e.g., 10 requests = 10 hits. HTTP requests with the same IP, date, and user agent are considered a unique visit. Iykyk.
Wanna enable dual-stack support? Please use --addr=:: instead of the default --addr=0.0.0.0. ๐
The generated report will attempt to reconnect to the WebSocket server after 1 second with exponential backoff. It will attempt to connect 20 times. Determined little thing.
๐ BUGS ๐
If you think you've found a bug, please send an email to goaccess@prosoftcorp.com or use the issue tracker at https://github.com/allinurl/goaccess/issues. We appreciate you ๐ซถ
๐ AUTHOR ๐
Gerardo Orellana <hello@goaccess.io>. For more details about it, or new releases, please visit https://goaccess.io.
That's the whole page, bestie โ you made it to the end ๐ This gem is goaccess(1) from the GNU+Linux fam, dated JUL 2026. Go parse some logs and live your truth โจ๐๐ธ
๐ฆ where this page comes from
- arch rolling: goaccess 1.12-1 ยท MIT
- nixpkgs unstable: goaccess 1.12
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms