Hi, I have run "Swift build --configuration release" and I have the release version of my backend. Maybe I'm totally misunderstanding but after this but what I do next is to copy the Dockerfile and the contents of the .build/release folder into a Package/ folder so I can then zip it and then upload it when creating a new environment.
Can someone help me through the steps of properly deploying a Vapor backend to Elastic beanstalk? I'd even be open to alternatives to EB
#Can't host Vapor Backend on Elastic Beanstalk
1 messages · Page 1 of 1 (latest)
I think AppRunner is probably the easiest way on AWS
However EB should support docker containers
What steps did you follow to set it up?
I really couldn't find steps to deploy on Beanstalk to be honest. I had to ask ChatGPT. This is just the backend for an iOS Application too.
- I create the Vapor app template, set everything up
2.I ran Swift build --configuration release to get the release version, keeping in mind I should my dockerfile and image already created from what I understand. This is where my mind started to go to different places because I know that a container should be hosted in a container registry so I followed the steps to upload my container onto ECR, thinking I could use the ECR URL to point to my container when creating an environment...it did not work - My next thoughts are to just do what ChatGPT says in the screenshot I have attached. So I've built a release version of the backend, now I just have to package it and compress it to a Zip and upload it to the environment..which is what I tried.
I'm trying to use AppRunner, I've built the container using docker buildx --platform linux/arm64 .....I keep getting this error regardless of whether I specify the CPU architecture or not : 07-29-2023 11:31:16 AM exec ./App: exec format error
@elfin hollow AppRunner is intel/amd64 only (last I checked)
What machine are you building docker images on? You'll need to build intel docker images.
I'm building on Apple Silicon
Ohhh so is "docker buildx --platform linux/amd64 what I'd be looking for"? I'm assuming by default I've been building for apple silicon with or without the additional flags.
I'm not familiar with building intel images from an arm machine. I believe you're supposed to be able to do that, but I've heard it's slow. It might have gotten better with Docker's experimental (?) support for Rosetta.
I'm still running an intel machine, but a while ago I switched to building my docker images on GH runners in preparation for eventually switching to an M2/M3 machine in the future. You may consider trying that.
I saw this as an option and I think I may have to try it.
Heroku for now tho

nothing against Heroku though butI'd rather have done this the first time with AppRunner
I believe AppRunner will build your code for you, but I don't know how it works and if it support swift. You may want to check that out.
You should also confirm that they haven't added arm support.
it doesn't that's the thing, I think
It has support for Python, NodeJS...etc
and you even still need the apprunner.yaml file too
If you need a GH runner .yml file I can probably dig one up for you.
That'd actually be great. Thank you
Ok, @elfin hollow , this is my GH action file that has been sanitized and cleaned up a bit.
A couple of notes:
- This builds and then pushes the images to both Docker.io and AWS ECR
- There is a little extra complication added because I like to grab the git branch, tag and hash information and send it through as env variable to my Vapor app so that I can confirm what version is running live
- This triggers on tags matching "**devar" which is what I tag my commits with if I want to run a build. You can modify this to be tag or branch based.
- You'll need to modify the AWS regions if your ECR is held somewhere other than
us-west-2 - This pulls secrets setup in GH, if you need those portions you'll have to set them up for yourself in GH
- You'll need to configure the path to your dockerfile correctly at the end of the
docker buildcall - IIRC
uses: aws-actions/configure-aws-credentials@v1-node16oraws-actions/configure-aws-credentials@v1-node16relies on a connection between GH and AWS ECR that has to be configured independently, but GH/AWS had decent instructions when I set it up.
Thank you! I'm going to try this tonight! Fingers crossed I can get a working build haha
@native panther now has 13
!
@native panther Thanks so much! It took me a while but it worked . It's able to successfully deploy now!
@native panther now has 14
!
Glad to hear it!
It deploys but I get a bunch of errors hahaha
07-30-2023 01:18:28 AM Swift/ErrorType.swift:200: Fatal error: Error raised at top level: Error Domain=NSURLErrorDomain Code=-1000 "(null)"
07-30-2023 01:18:28 AM [ WARNING ] Error Domain=NSURLErrorDomain Code=-1000 "(null)"
Was the GitHub to AWS connector the hard part?
Where are you using URL? For your DB configuration?
learning the format of the workflow file and plugging my own stuff in as well as connecting GitHub to AWS were all hard but I was able to fix it. I had to remove the part where it is logging into Docker Hub, that was a blocker
In all honesty I'm not even sure how the environment get works but I've changed the fields in the Dockerfile
Based on your error, it looks like there’s some sort of error related to the URL. I’ve been trying to work through that new URL api just over the last 24h, so I don’t have it all figured out yet.
Oh, I see it
let databaseURL = Environment .get ("DATABASE_PORT") probably needs to be something different.
Oh!
changed it
I was following the deployment guide for Heroku, if the first if let needed for AWS?
You'll need a full URL for the subsequent SQLPostgresConfiguration (url: databaseURL) call to work.
The way that if let block is supposed to work is to choose between the different code paths for configuring the database.
ohh so with the https://
The first part is if you're using a URL for the configuration vs. all of that information broken out into parameters.
The URL would need to look something like postgres://username:password@localhost:5432/DatabaseName?sslmode=prefer
If you're not using the URL configuration then you can probably remove the whole thing. The alternative would be make let databaseURL = Environment .get ("DATABASE_URL") and DO NOT include a DATABASE_URL parameter in your environment.
this is what I was diong before actually. I didn't hve the DATABASE_URL parameter set up but I had a DATABASE_HOST parameter set up
even though they will be the same thing right?
No, you don't want them to be the same thing in this case. Not including the Database URL param in your env setup will cause you to go through the second code path, which sounds like how your env file is setup.
How are you loading env variables? with an .env file or configuring it in a UI?
Here, to make the point clear. I'd just replace the whole if/else block with the code from the else portion.
That'll simplify things for you.
I think this is the best bet
I'm passing them through when I create the App in AppRunner
but I also see them set up in the docker-compose file too
Why are you using a compose file?
What are you configuring with your compose file?
the compose file came with the project I think. So I've just been going along with it
The compose file won't come into play if you're deploying on apprunner
ahhhh
ok that clears things up for me a lot. So that means Passing it in through the UI or an ENV file would be better
Yea, for apprunner that's how you'll want to do it.
okok, well I've good thing i've already been doing that haha
depending on how you're deploying and configuring your app runner that's probably the easiest way to get started.
definitely. I'm hoping this changes everything haha.
I was trying to make get/post requests with insomnia and I was getting a 500 error , which makes sense
I'm checking the Application logs and I'm getting this too
it's rollingback now
yea, this is actually the same error I'm digging into right now.
I haven't gotten to confirm everything yet, but I think I have a path forward on fixing this. You can see the conversation with Gwynne over here: #fluent message
Definitely! Will take a look when I arrive home
wow that's a lot hahaha @native panther I'm not even sure I understand what's going on there .
yea, it's a bit complicated. Long story short, encryption is complicated and you need to tell the SSL system to trust amazon's cert.
I'm trying to get a finalized implementation together in that thread for you to use. I'm currently stumbling on loading the file though the package.swift resources system, but I've got a backup plan if necessary (just load it as base64 data from a string in the env file).
Thank you so much 🙏 I really appreciate it!
@native panther now has 15
!
Ok, I think I got it figured out (deploying now to confirm on apprunner. My solution looks like this:
/// Setup database
var sqlPsqlConfig = try SQLPostgresConfiguration(url: psqlUrl)
// setup TLS trust store to trust amazon CA cert
let localPath = "/Users/js/code/PSVapor/PSVaporV4/Sources/App/TLSSupport/global-bundle.pem"
let bundlePath = "./TLSSupport/global-bundle.pem"
var tlsConfig = TLSConfiguration.makeClientConfiguration()
if let localRootCert = try? NIOSSLTrustRoots.certificates(NIOSSLCertificate.fromPEMFile(localPath)) {
// only config tls/ssl when connecting to cloud database (has "amazonaws.com" in the url
if let hostString = psqlUrl.host(), hostString.contains(#/amazonaws.com/#) {
tlsConfig.trustRoots = localRootCert
sqlPsqlConfig.coreConfiguration.tls = .require(try .init(configuration: tlsConfig))
}
}else {
tlsConfig.trustRoots = .certificates(try NIOSSLCertificate.fromPEMFile(bundlePath))
sqlPsqlConfig.coreConfiguration.tls = .require(try .init(configuration: tlsConfig))
}
app.databases.use(DatabaseConfigurationFactory.postgres(configuration: sqlPsqlConfig),
as: .psql,
isDefault: true)
Sounds good I'm gonna try it as well
I think yours will look like this:
/// Setup database
var sqlPsqlConfig = try SQLPostgresConfiguration(
hostname: Environment.get("DATABASE_HOST' ) ?? "localhost",
port: Environment .get ("DATABASE_PORT").flatMap(Int.init(_:)) ?? 5432,
username: Environment.get("DATABASE_USERNAME") ?? "vapor_username",
password: Environment.get("DATABASE_PASSWORD") ?? "vapor _password",
database: Environment.get("DATABASE_NAME") ?? "vapor_database",
tls: .disable)
// setup TLS trust store to trust amazon CA cert
let localPath = "/Users/js/code/PSVapor/PSVaporV4/Sources/App/TLSSupport/global-bundle.pem"
let bundlePath = "./TLSSupport/global-bundle.pem"
var tlsConfig = TLSConfiguration.makeClientConfiguration()
if let localRootCert = try? NIOSSLTrustRoots.certificates(NIOSSLCertificate.fromPEMFile(localPath)) {
// only config tls/ssl when connecting to cloud database (has "amazonaws.com" in the url
if let hostString = psqlUrl.host(), hostString.contains(#/amazonaws.com/#) {
tlsConfig.trustRoots = localRootCert
sqlPsqlConfig.coreConfiguration.tls = .require(try .init(configuration: tlsConfig))
}
}else {
tlsConfig.trustRoots = .certificates(try NIOSSLCertificate.fromPEMFile(bundlePath))
sqlPsqlConfig.coreConfiguration.tls = .require(try .init(configuration: tlsConfig))
}
app.databases.use(.postgres(configuration: sqlPsqlConfig,
as: .psql,
isDefault: true)
Ohh I see. The PEM file..... how would I obtain that?
Yea, I was working my way that direction. You'll need to do the following:
- download the .pem file from aws here: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html (I used this one - https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem)
- add that file to your project under the
Sources/App/(App could be named different for you). I put mine in a new folder atSources/App/TLSSupport/global-bundle.pem. [see image] - Add that path to your
package.swift[see image]
Create encrypted connections to your Amazon RDS DB instance using SSL/TLS.
Ohhhh okok. I'm going to try that now! I appreciate your help and supprt on this!!
I'm happy to help. I'm trying to pay it forward after years of help around here.
(I started as a mechanical engineer hanging around here trying to build a passion project)
That's amazing and really inspiring I'm also trying my bestto learn as much as I can so I can know enough to help others who might need help so Thank you!
@native panther now has 16
!
just wanted to confirm the psqlUrl should be the url for the database correct? @native panther
If you want to use the URL approach, your URL will need to look like this: postgres://DATABASE_USERNAME:DATABASE_PASSWORD@DATABASE_HOST:DATABASE_PORT/DATABASE_NAME?sslmode=require
I kinda like doing it that way because I only have 1 env variable to manage in the env file and check for when I'm configuring the app.
ahh I see. I wanted to confirm that the comment is really just a check for if we're connecting to amazonaws.
Just tried it and it says failed to load the certificate for me. Were yuo able to deploy smoothly? @native panther
I got an error for using the host() function on Linux, I’ll have to fix it when I get back to the house.
Give me ~15 min
oh okok sounds good. I'll keep at it
I've validated this on docker locally, but pushing to aws to finalize the confirmation, but I think I got to the bottom of it.
The package.swift needed to be updated to load the directory and not only the single file like so:
resources: [
.copy("TLSSupport/")
]
And the bundle path needed to be updated to this:
let bundlePath = "./PSVaporV4_App.resources/TLSSupport/global-bundle.pem"
oh , that's interesting. The previous way made a lot of sense to me too. Here's hoping that AWS will accept it haha
It's all doing the same thing as before, just updating my understanding of how the package resources work.
Ok, my GH build and apprunner deploy worked successfully! 🎉
🥳
and you can acces your endpoints?
yep, access works
wow.... so those two changes did the trick then
I guess it makes sense though, Provide access to the folder with the resources. The bundle path it a bit weird to me though
so it would be ./App.resources/<anyother/folders>/global-bundle.pem ?
I'm assuming the _ is a naming convention of yours aha
honestly, I'm not super sure how that part is built. I think it's done by apple as part of how the bundle is built.
my project is called Lip-Backend, would this be the corresponding bundlePath? :
let bundlePath = "./Lip-Backend_App.resources/TLSSupport/global-bundle.pem"
I figured mine out by building the docker image and then digging through the image using $ docker image save psvapor:0.10.2.6.dev > suspect-image.tar and making sure that aligned with what I saw as output when running the below code as part of a local docker compose setup:
let fm = FileManager.default
let path = Bundle.main.resourcePath!
do {
let items = try fm.contentsOfDirectory(atPath: path)
for item in items {
print("Found \(item)")
}
} catch {
// failed to read directory – bad permissions, perhaps?
}
I'm currently working on switch to the new @main template. I can let you know if that changes anything incase that's relevant.
It doesn't seem to change anything switching. I believe the resource package name is derived using PACKAGE_NAME underscore TARGET_NAME dot "resources". You can see my package.swift in this image:
this is what I assumed as well
and I guess that format also makes sense in itself
public func configure(_ app: Application) throws {
// uncomment to serve files from /Public folder
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
/// Setup database
var sqlPsqlConfig = SQLPostgresConfiguration(
hostname: Environment.get("DATABASE_HOST" ) ?? "localhost",
port: Environment .get ("DATABASE_PORT").flatMap(Int.init(_:)) ?? 5432,
username: Environment.get("DATABASE_USERNAME") ?? "vapor_username",
password: Environment.get("DATABASE_PASSWORD") ?? "vapor _password",
database: Environment.get("DATABASE_NAME") ?? "vapor_database",
tls: .disable)
// setup TLS trust store to trust amazon CA cert
let localPath = "/Users/dara/Documents/Development/Lip/Lip-Backend/Sources/App/TLSSupport/global-bundle.pem"
//let bundlePath = "./Lip-Backend_App.resources/TLSSupport/global-bundle.pem"
if let bundlePath = Bundle.main.url(forResource: "global-bundle", withExtension: "pem")?.absoluteString {
var tlsConfig = TLSConfiguration.makeClientConfiguration()
if let localRootCert = try? NIOSSLTrustRoots.certificates(NIOSSLCertificate.fromPEMFile(localPath)) {
tlsConfig.trustRoots = localRootCert
sqlPsqlConfig.coreConfiguration.tls = .require(try .init(configuration: tlsConfig))
}else {
tlsConfig.trustRoots = .certificates(try NIOSSLCertificate.fromPEMFile(bundlePath))
sqlPsqlConfig.coreConfiguration.tls = .require(try .init(configuration: tlsConfig))
}
}
app.databases.use(.postgres(configuration: sqlPsqlConfig), as: .psql, isDefault: true)
app.migrations.add(CreateDeal())
app.migrations.add(CreateUser())
try app.autoMigrate().wait()
// register routes
try routes(app)
}
Tried this also...did not work hahaha
im gonna get some rest for now before trying again to find my globa-bundle.pem file
if let bundlePath = Bundle.main.url(forResource: "global-bundle", withExtension: "pem")?.absoluteString looks funny.
If you want to use this approach, I think you'll need to use Bundle.module.
And, you'd probably need to use the .url(forResource: String, withExtension: String, subdirectory: String) method if you added the using .copy("TLSSupport/").
thats true , thank you!
@native panther now has 17
!
Running it locally for the first time in a while , I think I may see where some of my problems are coming from
it expects a .env file .
Yea, you’ve got an error with your env file somewhere. Are you also configuring your DB connection bears on info in the .env file?
I never had an .env file 🥲
If you can send your setup code I can try to help you though this. I take it your running this through docker compose, is that right?
correct
Getting the env file setup with compose takes a little work, but it’s doable.
that's true. I'll make the latest push and link it now
[email protected]:DaraAdekore/Lip-Backend.git
ah, the .env files were rightfully ignored, wondered why I didn't see them for a sec
The local docker compose I"m running still seems ot have an issue finding the .env file
Can you show the docker compose file and the dockerfile?
of course
# Docker Compose file for Vapor
#
# Install Docker on your system to run and test
# your Vapor app in a production-like environment.
#
# Note: This file is intended for testing and does not
# implement best practices for a production deployment.
#
# Learn more: https://docs.docker.com/compose/reference/
#
# Build images: docker-compose build
# Start app: docker-compose up app
# Start database: docker-compose up db
# Run migrations: docker-compose run migrate
# Stop all: docker-compose down (add -v to wipe db)
#
version: '3.7'
volumes:
db_data:
x-shared_environment: &shared_environment
LOG_LEVEL: ${LOG_LEVEL:-debug}
DATABASE_HOST: lip-database.ci59mhk01fma.us-west-2.rds.amazonaws.com
DATABASE_NAME: lip-database
DATABASE_USERNAME: masteruser
DATABASE_PASSWORD: opensesame123
DATABASE_PORT: 5432
services:
app:
image: lipcontainer:latest
build:
context: .
environment:
<<: *shared_environment
depends_on:
- db
ports:
- '8080:8080'
# user: '0' # uncomment to run as root for testing purposes even though Dockerfile defines 'vapor' user.
command: ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"]
migrate:
image: lipcontainer:latest
build:
context: .
environment:
<<: *shared_environment
depends_on:
- db
command: ["migrate", "--yes"]
deploy:
replicas: 0
revert:
image: lipcontainer:latest
build:
context: .
environment:
<<: *shared_environment
depends_on:
- db
command: ["migrate", "--revert", "--yes"]
deploy:
replicas: 0
db:
image: postgres:15-alpine
volumes:
- db_data:/var/lib/postgresql/data/pgdata
environment:
PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_USER: vapor_username
POSTGRES_PASSWORD: vapor_password
POSTGRES_DB: vapor_database
ports:
- '5432:5432'
This is the docker compose file @native panther
# ================================
# Build image
# ================================
FROM swift:5.8-jammy as build
# Install OS updates and, if needed, sqlite3
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
&& apt-get -q update \
&& apt-get -q dist-upgrade -y\
&& rm -rf /var/lib/apt/lists/*
# Set up a build area
WORKDIR /build
# First just resolve dependencies.
# This creates a cached layer that can be reused
# as long as your Package.swift/Package.resolved
# files do not change.
COPY ./Package.* ./
RUN swift package resolve
# Copy entire repo into container
COPY . .
# Build everything, with optimizations
RUN swift build -c release --static-swift-stdlib
# Switch to the staging area
WORKDIR /staging
# Copy main executable to staging area
RUN cp "$(swift build --package-path /build -c release --show-bin-path)/App" ./
# Copy resources bundled by SPM to staging area
RUN find -L "$(swift build --package-path /build -c release --show-bin-path)/" -regex '.*\.resources$' -exec cp -Ra {} ./ \;
# Copy any resources from the public directory and views directory if the directories exist
# Ensure that by default, neither the directory nor any of its contents are writable.
RUN [ -d /build/Public ] && { mv /build/Public ./Public && chmod -R a-w ./Public; } || true
RUN [ -d /build/Resources ] && { mv /build/Resources ./Resources && chmod -R a-w ./Resources; } || true
# ================================
# Run image
# ================================
FROM ubuntu:jammy
# Make sure all system packages are up to date, and install only essential packages.
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
&& apt-get -q update \
&& apt-get -q dist-upgrade -y \
&& apt-get -q install -y \
ca-certificates \
tzdata \
# If your app or its dependencies import FoundationNetworking, also install `libcurl4`.
# libcurl4 \
# If your app or its dependencies import FoundationXML, also install `libxml2`.
# libxml2 \
&& rm -r /var/lib/apt/lists/*
# Create a vapor user and group with /app as its home directory
RUN useradd --user-group --create-home --system --skel /dev/null --home-dir /app vapor
# Switch to the new home directory
WORKDIR /app
# Copy built executable and any staged resources from builder
COPY --from=build --chown=vapor:vapor /staging /app
# Ensure all further commands run as the vapor user
USER vapor:vapor
# Let Docker bind to port 8080
EXPOSE 8080
# Start the Vapor service when the image is run, default to listening on 8080 in production environment
ENTRYPOINT ["./App"]
CMD ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"]
This is the dockerfile
I used to use the x-shared_environment: &shared_environment method, but I found it frustrating. That was so long ago that I don't know why though. You might just want to try loading an .env file.
This is what mine looks like:
version: "3.7"
services:
api:
#build:
#context: .
#dockerfile: Dockerfile-dev
#image: api:dev
image: daskier/psvapor:latest.dev #alt: daskier/psvapor:latest.dev
env_file:
- ../.env.development
ports:
- "8080:8080"
I believe my dockerfile is functionally the same as yours.
BTW - double check how vapor loads the environment variables. I don't remember if those warnings/debug messages always come up if you have your logging levels set super low. The easiest thing to do is try to access your env vars with a guard statement and log the error if the item you're looking for isn't available and you can throw a fatalError("ENV var not found")
I tried using the env_file but I may have used it wrong
One thing that I found confusing (and I still don't recall the correct answer) is if the search path for the env file is with respect to where you are running the command from or where the dockerfile is stored.
so relative to the dockerfile
that's what I"m thinking too
could it be because I've been trying to use .env.production?
instead of just .env?
That .env.production is how vapor looks for the env files if it were searching on disk within the working directory, but in the case of docker it will look for the file itself and then load the variables into the ENV for you.
So, this is why when you startup vapor with the logging level set to a low threshold, you'll see vapor looking for the .env.production file and not finding it. But, that's ok, because Docker will load the ENV vars for you.
(My description may be slightly off, but the end outcome should be correct - when providing docker with your env file you don't need to worry about vapor's access to the .env.file)
Yes. So, like I said, the best way I've found to be super sure the ENV has what I want accessible I just do a lot of log based debugging to ensure everything is correct the first run through.
You have to be careful about this with publicly available resources or executing those things on public cloud instances because it could end up logging sensitive information like logins/passwords/keys. I usually do this with dummy data to avoid that problem.
You're right! Logging it worked
What is your error at this point?
when I run it in Xcode or try compose up app , I get this.
I'm deploying to AppRunner now to see what happens
There's a chance that this has to do with the database config.
AppRunner will automatically rollback when I see this 
Yea, that error will mean that your app never responds to the health check, so apprunner will automatically roll back to the last known good state.
Show me your db config code once more?
I just removed the if let for the global resource code I had earlier and this is what I have now :
import NIOSSL
import Fluent
import FluentPostgresDriver
import Vapor
// configures your application
public func configure(_ app: Application) throws {
guard (Environment.get("DATABASE_HOST" ) != nil),
(Environment.get("DATABASE_PORT").flatMap(Int.init(_:)) != nil),
Environment.get("DATABASE_USERNAME") != nil,
Environment.get("DATABASE_PASSWORD") != nil,
Environment.get("DATABASE_NAME") != nil else {
fatalError("Error ENV Variable not found")
}
print("host : \(Environment.get("DATABASE_HOST" ))")
print("port: \(Environment.get("DATABASE_PORT"))")
print("username: \(Environment.get("DATABASE_USERNAME"))")
print("password : \(Environment.get("DATABASE_PASSWORD"))")
print("\(Environment.get("DATABASE_NAME"))")
// uncomment to serve files from /Public folder
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
/// Setup database
var sqlPsqlConfig = SQLPostgresConfiguration(
hostname: Environment.get("DATABASE_HOST" ) ?? "localhost",
port: Environment.get("DATABASE_PORT").flatMap(Int.init(_:)) ?? 5432,
username: Environment.get("DATABASE_USERNAME") ?? "vapor_username",
password: Environment.get("DATABASE_PASSWORD") ?? "vapor _password",
database: Environment.get("DATABASE_NAME") ?? "vapor_database",
tls: .disable)
// setup TLS trust store to trust amazon CA cert
let localPath = "/Users/dara/Documents/Development/Lip/Lip-Backend/Sources/App/TLSSupport/global-bundle.pem"
let bundlePath = "./Lip-Backend_App.resources/TLSSupport/global-bundle.pem"
var tlsConfig = TLSConfiguration.makeClientConfiguration()
if let localRootCert = try? NIOSSLTrustRoots.certificates(NIOSSLCertificate.fromPEMFile(localPath)) {
tlsConfig.trustRoots = localRootCert
sqlPsqlConfig.coreConfiguration.tls = .require(try .init(configuration: tlsConfig))
}else {
tlsConfig.trustRoots = .certificates(try NIOSSLCertificate.fromPEMFile(bundlePath))
sqlPsqlConfig.coreConfiguration.tls = .require(try .init(configuration: tlsConfig))
}
app.databases.use(.postgres(configuration: sqlPsqlConfig), as: .psql, isDefault: true)
app.migrations.add(CreateDeal())
app.migrations.add(CreateUser())
try app.autoMigrate().wait()
// register routes
try routes(app)
}
That line message: no pg-hba.conf entry for host "54.70.103.169", user "masteruser", database "Lip-database", no encryption, gives me pause. I'm not familiar with that.
That looks like a DB configuration issue. I'm not sure how that arises in an RDS DB though.
It might be worth posting that in #fluent
It'd probably be helpful to read this too: https://www.postgresql.org/docs/current/auth-pg-hba-conf.html
Yeah
Apparently RDS is meant to cover the whole configuration for the DB abstracting it to just the UI that we see
I get it when runnning locally too so that makes me think it's not an issue with RDS
I was forgetting to up the database hahaha
this is better!
these are my DB configurations on RDS actually
the global-bundle.pem should work with this right?
Yea, the global-bundle.pem should work with that. I'm using the same Certificate Authority option.
What security group is your apprunner instance in?
how would I find that?
chekcing the configuration settings for it and I'm not sure i see it
But locally: I was not pointnig to my local database now I'm getting this error lip-backend-app-1 | [ WARNING ] PSQLError(code: sslUnsupported)
lip-backend-app-1 | Swift/ErrorType.swift:200: Fatal error: Error raised at top level: PSQLError(code: sslUnsupported)
Under apprunner configuration:
Ok, sslUnsuported makes sense for your local. I was getting the same thing. That's why you see in my config.swift file that I don't set the tls settings to require if the localRootCert exists AND the database url doesn't include amazonaws.com.
So, when connecting to my local database ssl isn't required and when connecting to RDS it will require the ssl.
Are you able to directly connect to your RDS instance from your local machine? (I setup a security group for my local ip address to access my RDS instance)
Because if you can, you can test this whole setup from your local machine.
I believe I can connect to it from Azure Data Studio
no tables or anything yet tho I think so there's nothing to query
If that's a local app then you can probably connect. You could try with an app like postico or TablePlus or similar.
Or just psql command line.
If that works then you could feel confident testing your app from xcode with the connection parameters set for RDS.
okI see, I'll try that now
oh
it iddn't work
I get this
Password for user masteruser:
psql: error: connection to server at "lip-database.ci59mhk01fma.us-west-2.rds.amazonaws.com" (44.235.170.101), port 5432 failed: FATAL: database "lip-database" does not exist
This is the command I used to verify my connection: psql -h hostname.us-west-2.rds.amazonaws.com -p 5432 "dbname=dbName user=userName sslrootcert=/Users/js/code/PSVapor/PSVaporV4/Sources/App/TLSSupport/global-bundle.pem sslmode=verify-full"
Lip-Backend % psql -h lip-database.ci59mhk01fma.us-west-2.rds.amazonaws.com -p 5432 "dbname=lip-database user=masteruser sslrootcert=/Users/dara/Documents/Development/Lip/Lip-Backend/Sources/App/TLSSupport/global-bundle.pem sslmode=verify-full"
Password for user masteruser:
psql: error: connection to server at "lip-database.ci59mhk01fma.us-west-2.rds.amazonaws.com" (44.235.170.101), port 5432 failed: FATAL: database "lip-database" does not exist
Still the same thingit seems
it verifiably exists too
Can you try with sslmode=allow?
I can try that
but what theheck
DB name is blacnk
are the instance ID and the DB name not the same?
it's modifying right nwo so I can't check the settings but I could have sworn I set that.
Mine does have a name:
They don't have to be the same:
Database name is also part of my terraform config for creating the RDS instance:
You may want to create a new RDS DB just to see if that changes anything for you.
I can't see it in the UI for the RDS instance :O
I think I may have to delete and recreate it
Ok I figured it out. I think it's because I'm using the free tear?
psql -h lip-database.ci59mhk01fma.us-west-2.rds.amazonaws.com -p 5432 "dbname=postgres user=masteruser sslrootcert=/Users/dara/Documents/Development/Lip/Lip-Backend/Sources/App/TLSSupport/global-bundle.pem sslmode=verify-full"
Password for user masteruser:
psql (15.3)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, compression: off)
Type "help" for help.
``` this is what it should look like if you've succesfully connected right?
Yea, this is what mine looks like with a successful conection:
I think that is the default DB name.
You can probably create another database with a different name through the PSQL tool if you want.
But, for now you can probably test these configuration values with your project.
exactly
works in Xcode
We got it 😎 @native panther
Congratulations!
You did this !
I feel like I should make a post on medium about thisbhahaha
Just to help others who might be in the same situation
Yea, I’ve been thinking the same.
I think there’s a post in the tls setup
There’s another part in there about the dynamic config for local vs. cloud
I’ve been trying to use the new App Store Connect server library from Apple recently and there’s a post in there too.
Ohh ok could you link it if possible?
I'm currently trying to figure out Relations. From it seems they're useful for querying from a database and not creating or updating.