Deploy Uptimy Agent on Railway

Deploy the agent into your Railway project from the template, sign in, and monitor every service in the project over private networking. About five minutes.

Overview

Uptimy Agent is an open-source monitor (Apache-2.0, on GitHub) that runs as a service in your Railway project. On the project's private network it checks what an outside monitor can't reach:

  • Services without a public domain, at <service>.railway.internal.
  • Postgres, MySQL, MariaDB and Redis, by logging in and running a query, so a full connection limit or a rejected password is caught too.
  • Cron services, as heartbeats that alert when a run doesn't check in.

It has its own UI, alert channels and public status page, and needs no account. The template is the quickest way to run it:

Uptimy Agent template on Railway

One service with a volume, a generated admin password and a public domain. Deploy it into the project you want to monitor.

What the template deploys

Imageghcr.io/uptimy/agent:latest
VolumeMounted at /data and backed up daily. The agent keeps everything here in one SQLite database: monitors, history, settings and users.
Public domainA generated *.up.railway.app domain on port 8080, for the UI and the status page at /status.
Healthcheck/healthz
Replicas1. SQLite has a single writer, so don't scale it out.

Environment variables

The template sets these. Keep the defaults when you deploy.

ADMIN_PASSWORDRequired · template value ${{secret(24)}}

The admin's password: 24 random characters, generated once when you deploy the template (at least 8 if you set your own).

RAILWAY_RUN_UIDRequired · template value 0

Runs the container as root so it can write to the volume, which Railway mounts as root. The image otherwise runs as a non-root user.

ADMIN_USERNAMEOptional · template value admin

The admin's username.

Variables you can add later:

POSTGRES_URL, REDIS_URL, ...No default

Connection URLs for database checks, as reference variables such as ${{Postgres.DATABASE_URL}}. Monitors use them as ${POSTGRES_URL}, so database passwords stay in Railway and never reach the agent's database. The import below tells you which to add.

MONITORS_YAMLNo default

Monitors as YAML, kept in Railway with the rest of the project. See Monitors as code.

AGENT_NAMEDefault: the hostname

How the agent is labeled in Uptimy Cloud. On Railway the hostname is a container ID, so set a name if you connect it.

RETENTION_DAYSDefault 30

How long check results, heartbeat runs, events and alerts are kept. Daily uptime history is kept for 400 days either way.

Leave PORT unset: the domain points at 8080, where the agent listens by default. Railway sets RAILWAY_PROJECT_ID, RAILWAY_ENVIRONMENT_ID and RAILWAY_SERVICE_ID on every deployment, and the agent reads them to know which project it's in. All settings are in the configuration reference.

1. Deploy the template

Click Deploy on Railway above, keep the variables as they are and deploy. To add the agent to a project you already have, open the project and choose + New → Template, then search for Uptimy Agent.

ℹ️ Same project, same environment

The agent reaches private addresses only in its own project and environment. Deploy it next to the services you want to monitor. From another project it can still check their public domains.

The deploy takes about a minute. Railway marks it active once /healthz answers.

2. Sign in

Open the service's domain, shown on the service and under Settings → Networking. Sign in as admin with the value of ADMIN_PASSWORD from the service's Variables tab.

While ADMIN_PASSWORD is set, that password is managed in Railway, not in the agent: change the variable and redeploy to set a new one. That's also how you get back in after losing it.

Add the people who need access under Users, as admins or viewers. Each of them can turn on two-factor sign-in under Account.

3. Add an alert channel

Under Notifications, add a channel: Slack, Discord, Teams, Telegram, email, ntfy, PagerDuty, a webhook, or one of 30+ more through Shoutrrr. New channels alert for every monitor, including the ones you add later, so one channel is all the alerting setup you need.

4. Import the services in your project

  1. In Railway, create a project token under Project → Settings → Tokens, for the environment the agent runs in.
  2. In the agent, open Settings → Import from Railway, paste the token and click Preview services.
  3. Review the monitors, fill in anything missing, and click Import.

Every other service in the environment becomes a monitor:

  • Web services: an HTTP check at <service>.railway.internal on the service's healthcheck path. If Railway doesn't know the port the service listens on, the review asks for it. Switch to Public to check the public domain instead.
  • Postgres, MySQL, MariaDB and Redis: a database check through a variable on the agent, named after the service. For a service called Postgres, add POSTGRES_URL with the value ${{Postgres.DATABASE_URL}} to the agent and deploy the change.
  • Cron services: a heartbeat on the service's cron schedule, in UTC like Railway runs it. Add curl -fsS <ping URL> as the job's last step. After importing, the new heartbeats are listed with links to their pages, which show the ping URL to admins.

The token is only used to read the services and isn't stored. Importing again skips services already imported, so run it again after adding services.

Monitors as code

Instead of importing, or next to it, put monitors in the MONITORS_YAML variable. Railway fills in ${{...}} references when it deploys, so a target follows the service's private hostname. The agent fills in ${...} in database targets when a check runs.

MONITORS_YAML
healthchecks:
  - name: API
    type: http
    target: http://${{api.RAILWAY_PRIVATE_DOMAIN}}:8080/health
  - name: Postgres
    type: postgres
    target: ${POSTGRES_URL}
heartbeats:
  - name: Nightly backup
    cron: "0 3 * * *"
    grace: 30m

Monitors from YAML are matched by name, so editing one keeps its history. They show read-only in the UI. A mistake doesn't stop the agent: the rest is applied and the error is shown on the dashboard.

5. Publish the status page

Under Status page, add the monitors visitors should see. It's public at https://<your-domain>/status and never shows targets or internal hostnames. To serve it on a domain such as status.example.com, add the domain to the service in Railway's networking settings and enter it under Status page → Custom domain. That domain serves only the status page, so sign-in stays on the Railway one. Here's the live demo, an agent running on Railway.

When the agent itself goes down

A monitor can't report its own outage. In the agent, Settings → Uptimy Cloud connects it to a free Uptimy account. The agent uploads its results every minute (every 5 minutes on Free), and Uptimy alerts you from outside when the uploads stop. Its monitors show up in your workspace for status pages, SLA reports and workflows, without counting toward your plan's limits. See Connect to Uptimy Cloud.

Troubleshooting

  • A private check fails but the public domain works: compare the hostname with the service's private networking settings and check the port. In Railway environments created before October 16, 2025, private names resolve to IPv6 only, so the service has to listen on ::.
  • A database check says a variable isn't set: add the reference variable it names to the agent service and deploy the change.
  • Monitors are gone after a redeploy: the volume must be mounted at /data.
  • The admin password doesn't work: it's the current value of ADMIN_PASSWORD. Set a new one there and redeploy.

Next steps