Customizing environment variables and secrets for a Dockerized Vapor server bridges mobile app development with backend security and DevOps best practices. iOS developers working with Swift-based Vapor servers need to securely manage API keys, database credentials, and other sensitive configurations, especially in containerized environments. This post explores how to set up, inject, and manage these secrets effectively within Docker, helping developers build more secure and scalable backend solutions while enhancing their understanding of environment-based configuration management.
In this post, we will configure a simple Vapor server and demonstrate how to set up custom environment variables and provide secrets to the app.
Hello Vapor Server
The first step is to create a Vapor project by entering the following command:
vapor new HelloServer You will be asked about Fluent and Leaf, but we will not be working with databases (Fluent) or HTML templates (Leaf).
Navigate to the created folder. In our case, we will use Xcode as the source code editor.
Open routes.swift file:
import Vapor
func routes(_ app: Application) throws {
app.get("hello") { req -> String in
let name = Environment.get("CUSTOM_VARIABLE") ?? "World"
return "Hello, \(name)!"
}
} The given Swift code defines a simple web route using the Vapor framework. It sets up a GET endpoint at «/hello», which returns a greeting message. The message includes a name retrieved from an environment variable called "CUSTOM_VARIABLE"; if this variable is not set, it defaults to "World". So, when a user accesses GET /hello, the server responds with "Hello, [name]!", where [name] is either the value of "CUSTOM_VARIABLE" or "World" if the variable is absent
Custom Configuration variables
During project creation one of the files generated was a Dockerfile, this file without any update will be used for building a Docker image:
docker build -t hello-vapor .
Finally we will run the container:
docker run -e CUSTOM_VARIABLE="Custom variable Value" -p 8080:8080 hello-vapor The command docker run -e CUSTOM_VARIABLE="Custom variable Value" -p 8080:8080 hello-vapor runs a Docker container from the hello-vapor image. It sets an environment variable CUSTOM_VARIABLE with the value "Custom variable Value" inside the container using the -e flag. The -p 8080:8080 flag maps port 8080 of the container to port 8080 on the host machine, allowing external access to any service running on that port inside the container.
The Vapor server is up and waiting for ‘hello’ GET requests. Open an new terminal session window and type following command.
curl http://localhost:8080/hello When we get back to server terminal window:
The endpoint implementation accesses the CUSTOM_VARIABLE environment variable and prints its contents.
Secrets
When we talk about transferring sensitive information such as keys, passwords, and API tokens, there is no perfect solution, as even the most secure methods come with potential vulnerabilities. Here’s an overview of common approaches and their security concerns:
Storing secrets in a .env file: This approach keeps secrets separate from the code but still requires careful management of the .env file to prevent unauthorized access.
Using Docker Secrets with Docker Compose: Docker Secrets allow you to store sensitive data in encrypted files, which can be mounted into containers. However, careful access control is necessary to prevent unauthorized retrieval.
Implementing a sidecar container for secret management: A separate container can handle secret retrieval and securely pass them to the main application container. Access control rules can be applied to limit access to a specific set of users.
Employing external secret management tools: Solutions like HashiCorp Vault or cloud-based key management services provide robust secret handling and enhanced security features, but they may introduce complexity in management.
In this guide, we will store the secrets in a .env file. The first step is to create a text file containing the key-value pairs, naming it .env.
echo "SECRET=Asg992fA83bs7d==" >> .env
Keep the file in a safe place but never in a repository.
Update endpoint code for also fetching SECRET:
import Vapor
func routes(_ app: Application) throws {
app.get("hello") { req -> String in
let name = Environment.get("CUSTOM_VARIABLE") ?? "World"
let secret = Environment.get("SECRET") ?? "---"
return "Hello, \(name)! secret is \(secret)"
}
}
Build a the new docker image:
docker build -t hello-vapor .
For executing container, as input parameter we provide the .env file that conains the secret:
docker run --env-file .env -p 8080:8080 hello-vapor Server iss ready again:
Calling endpoint again:
curl http://localhost:8080/hello
Secreta is now fetched by the endpoint.
Conclusions
For entering environment variables there is an standarized way of doing but we can not say the same when it comes to talk about secrets. Depending on the degree of security that we want to achieve we will have to apply one method or other.
You can find source code used for writing this post in following repository.
References
- Secrets in Docker
YouTube video
- keepin’ secrets on your pillow
JaviOS blog post