How to get the IP form the client

I need to get the IP from the client, how can I do this?
I tried ctx.request.ip but this returns localhost (

If a make console.log(ctx.request) I see this field

  method: 'GET',
  url: '/sub-categorias?categoria=1',
  header: {
    host: '',
    'sec-ch-ua': '" Not;A Brand";v="99", "Microsoft Edge";v="91", "Chromium";v="91"',
    authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNjI1MDEyNjY5LCJleHAiOjE2Mjc2MDQ2Njl9.EO5RwOeTrpxZkn7dC8rNRjyIMOAZPPUMJYBg7UW5uX8',
    'sec-ch-ua-mobile': '?0',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.64',
    accept: '*/*',
    'sec-fetch-site': 'none',
    'sec-fetch-mode': 'cors',
    'sec-fetch-dest': 'empty',
    'accept-encoding': 'gzip, deflate, br',
    'accept-language': 'es,es-ES;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
    'x-forwarded-proto': 'https',
    'x-forwarded-for': '' // ===> MY PUBLIC IP

But I’m not sure if it I will have this field on all the requests

Well… I tried with my phone to my local ip, and request.ip works. But if im using a proxy (like ngrok) it shows localhost, I dont know why

Ngrok doesn’t pass that header, depending if there is a proxy layer between the application or not Strapi sees the last IP “hop” that the request was coming from.

If Ngrok does support passing that header then you need to enable the setting that tells Strapi it’s behind a proxy (I don’t know if Ngrok does or not)

proxy: Set the koa variable app.proxy . When true , proxy header fields will be trusted.
IE: x-forwarded-for

More information about this header (I’m not going to dive into deep networking topics): X-Forwarded-For - HTTP | MDN

In which file would app.proxy will be set.

See that documentation link, look at the full example, the key is just called proxy and you set that to true

1 Like

Is it like this :

module.exports = ({ env }) => ({
  host: env('HOST', ''),
  port:'PORT', 1337),
  socket: '/tmp/nginx.socket', // only use if absolutely required
  emitErrors: false,
  url: env('PUBLIC_URL', ''),
  proxy: env.bool('IS_PROXIED', true),
  cron: {
    enabled: env.bool('CRON_ENABLED', false),
  admin: {
    auth: {
      events: {
        onConnectionSuccess(e) {
          console.log(e.user, e.provider);
        onConnectionError(e) {
          console.error(e.error, e.provider);
      secret: env('ADMIN_JWT_SECRET', 'someSecretKey'),
    url: env('PUBLIC_ADMIN_URL', '/dashboard'),
    autoOpen: false,
    watchIgnoreFiles: [
      './my-custom-folder', // Folder
      './scripts/', // File
    host: 'localhost', // Only used for --watch-admin
    port: 8003, // Only used for --watch-admin
    serveAdminPanel: env.bool('SERVE_ADMIN', true),
    forgotPassword: {
      from: '',
      replyTo: '',

Environment Variables (.env) :

1 Like

Exactly this, you don’t need everything in that full example, just wanted to point out here the proxy key was.