1---
2title: Custom domains, TCP & private networks
3description: Reach a Railway Service on your own hostname, expose databases over public TCP, and name private-mesh DNS.
4---
5
6HTTP [Services](/railway/compute/services) already get a generated
7`*.up.railway.app` hostname. That is enough for most apps. Add a
8[`CustomDomain`](/providers/railway/customdomain) for a hostname you
9control. Add a [`TcpProxy`](/providers/railway/tcpproxy) so a laptop
10or deploy-time migration can reach Postgres, MySQL, Mongo, or Redis.
11Named [`PrivateNetwork`](/providers/railway/privatenetwork)s add
12custom DNS on the default `*.railway.internal` mesh.
13
14## Publish the Service
15
16A Service with `port` listens inside the container. Alchemy creates
17a `*.up.railway.app` domain and points it at that port.
18
19```typescript
20export default class Api extends Railway.Service<Api>()(
21 "Api",
22 {
23 project: Site,
24 main: import.meta.url,
25 port: 3000,
26 },
27 Effect.gen(function* () {
28 return {
29 fetch: Effect.succeed(HttpServerResponse.text("hello")),
30 };
31 }),
32) {}
33```
34
35Yield the Service in the Stack. `api.url` is
36`https://{name}.up.railway.app`.
37
38```typescript
39export default Alchemy.Stack(
40 "MyApp",
41 { providers: Railway.providers(), state: Alchemy.localState() },
42 Effect.gen(function* () {
43 const api = yield* Api;
44 return { url: api.url };
45 }),
46);
47```
48
49There is no IpAssignment resource. Railway's edge terminates TLS on
50443.
51
52## Custom domains
53
54A CustomDomain is a user hostname on a Service. Railway issues a
55Let's Encrypt certificate once DNS is verified.
56
57```typescript
58const site = yield* Railway.Project("Site");
59const api = yield* Railway.Service("Api", {
60 project: site,
61 image: "hashicorp/http-echo",
62 port: 5678,
63});
64const www = yield* Railway.CustomDomain("Www", {
65 service: api,
66 environment: site,
67 domain: "www.example.com",
68});
69```
70
71Yield `Www` in the Stack. Point DNS at
72`www.verificationDnsHost` / `www.verificationToken`. `www.url` is
73`https://www.example.com`. `verified` flips once Railway sees the
74record.
75
76`targetPort` is optional and updates in place. Changing `domain`,
77`service`, or `environment` replaces the CustomDomain.
78
79```typescript
80const www = yield* Railway.CustomDomain("Www", {
81 service: api,
82 environment: site,
83 domain: "www.example.com",
84 targetPort: 8080,
85});
86```
87
88## TCP proxies
89
90A TcpProxy exposes a service over public TCP
91(`{domain}:{proxyPort}` on `*.proxy.rlwy.net`). Identity is the
92Railway proxy id. There is no in-place update — changing `service`,
93`postgres`, `redis`, `environment`, or `applicationPort` replaces
94the proxy.
95
96[`Railway.Postgres`](/railway/data/postgres),
97[`MySQL`](/railway/data/mysql), and [`Mongo`](/railway/data/mongo)
98already create one when `public` is true (the default). Use
99`TcpProxy` for Redis, or for a database created with `public:
100false`.
101
102```typescript
103const site = yield* Railway.Project("Site");
104const db = yield* Railway.Postgres("Db", { project: site, public: false });
105const proxy = yield* Railway.TcpProxy("DbProxy", {
106 postgres: db,
107 environment: site,
108 applicationPort: 5432,
109});
110```
111
112Redis on `6379`:
113
114```typescript
115const cache = yield* Railway.Redis("Cache", { project: site });
116const proxy = yield* Railway.TcpProxy("CacheProxy", {
117 redis: cache,
118 environment: site,
119 applicationPort: 6379,
120});
121```
122
123Pass a `Railway.Service` (or `{ serviceId }`) for any other
124container.
125
126In-service bindings (`ConnectPostgres`, `ConnectMySQL`,
127`ConnectMongo`, `ReadWriteRedis`) always use the private
128`{name}.railway.internal` URL. The TCP proxy is for laptops and CI.
129
130## Private networks
131
132Every environment already has the default `*.railway.internal` mesh
133— `{serviceName}.railway.internal` is derived from the Service name,
134no extra resource. [`PrivateNetwork`](/providers/railway/privatenetwork)
135create-or-gets an additional named network. Attach a Service with
136[`PrivateNetworkEndpoint`](/providers/railway/privatenetwork)
137for a custom DNS name.
138
139```typescript
140const net = yield* Railway.PrivateNetwork("Mesh", {
141 environment: site,
142});
143const endpoint = yield* Railway.PrivateNetworkEndpoint("ApiDns", {
144 network: net,
145 service: api,
146 name: "api",
147});
148```
149
150Railway has no per-network delete. Destroy is a no-op; the network
151is removed when its Project/Environment is deleted.
152
153## Where next
154
155The [tutorial](/railway/tutorial/part-2) deploys a Service that
156answers on `*.up.railway.app`. Custom domains and TCP proxies hang
157off the Service / Postgres / Redis. See the
158[`CustomDomain`](/providers/railway/customdomain),
159[`TcpProxy`](/providers/railway/tcpproxy),
160[`PrivateNetwork`](/providers/railway/privatenetwork) (includes
161`PrivateNetworkEndpoint`) references.